<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.sandbox.joomla.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ing+Pulizzi</id>
	<title>Joomla! Documentation - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.sandbox.joomla.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ing+Pulizzi"/>
	<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/Special:Contributions/Ing_Pulizzi"/>
	<updated>2026-10-16T16:24:26Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/Page_display_title/it&amp;diff=1001945</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/Page display title/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/Page_display_title/it&amp;diff=1001945"/>
		<updated>2023-05-27T13:35:05Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;J3.x:Sviluppo di un Componente MVC / Aggiornamento a Joomla 4&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001944</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001944"/>
		<updated>2023-05-27T12:48:26Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;===Caricamento automatico della classe===  Joomla utilizza il meccanismo PHP per [https://www.php.net/manual/en/language.oop5.autoload.php Classi di caricamento automatico] e...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;br /&gt;
&lt;br /&gt;
Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo namespace.&lt;br /&gt;
&lt;br /&gt;
Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altrimenti PHP cercherà di trovare nel tuo spazio dei nomi.&lt;br /&gt;
&lt;br /&gt;
Se utilizzi definizioni di campi o regole personalizzate nei tuoi file xml del modulo, devi indicare a PHP quale prefisso dello spazio dei nomi utilizzare per cercarli, ad esempio in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
    addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&lt;br /&gt;
e anche in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; dove le associazioni vengono aggiunte dinamicamente al modulo per formare il campo di tipo &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; personalizzato:&lt;br /&gt;
&lt;br /&gt;
    $fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&lt;br /&gt;
===Caricamento automatico della classe===&lt;br /&gt;
 Joomla utilizza il meccanismo PHP per [https://www.php.net/manual/en/language.oop5.autoload.php Classi di caricamento automatico] e all&#039;avvio registra una serie di caricatori automatici, funzioni che vengono chiamate quando PHP non riesce a trovare una data classe.  In particolare la funzione di Joomla PSR-4 autoloader (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) è responsabile della ricerca di classi di estensioni Joomla il cui codice si trova nei file sorgente che sono organizzati secondo la raccomandazione PSR-4.  (Le classi della libreria Joomla vengono caricate automaticamente utilizzando un caricatore automatico diverso – vedi &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/29/it&amp;diff=1001943</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/29/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/29/it&amp;diff=1001943"/>
		<updated>2023-05-27T12:48:19Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;===Caricamento automatico della classe===  Joomla utilizza il meccanismo PHP per [https://www.php.net/manual/en/language.oop5.autoload.php Classi di caricamento automatico] e...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===Caricamento automatico della classe===&lt;br /&gt;
 Joomla utilizza il meccanismo PHP per [https://www.php.net/manual/en/language.oop5.autoload.php Classi di caricamento automatico] e all&#039;avvio registra una serie di caricatori automatici, funzioni che vengono chiamate quando PHP non riesce a trovare una data classe.  In particolare la funzione di Joomla PSR-4 autoloader (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) è responsabile della ricerca di classi di estensioni Joomla il cui codice si trova nei file sorgente che sono organizzati secondo la raccomandazione PSR-4.  (Le classi della libreria Joomla vengono caricate automaticamente utilizzando un caricatore automatico diverso – vedi &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001942</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001942"/>
		<updated>2023-05-27T12:47:30Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;e anche in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; dove le associazioni vengono aggiunte dinamicamente al modulo per formare il campo di tipo &amp;lt;tt&amp;gt;modal_hellow...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;br /&gt;
&lt;br /&gt;
Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo namespace.&lt;br /&gt;
&lt;br /&gt;
Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altrimenti PHP cercherà di trovare nel tuo spazio dei nomi.&lt;br /&gt;
&lt;br /&gt;
Se utilizzi definizioni di campi o regole personalizzate nei tuoi file xml del modulo, devi indicare a PHP quale prefisso dello spazio dei nomi utilizzare per cercarli, ad esempio in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
    addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&lt;br /&gt;
e anche in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; dove le associazioni vengono aggiunte dinamicamente al modulo per formare il campo di tipo &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; personalizzato:&lt;br /&gt;
&lt;br /&gt;
    $fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/28/it&amp;diff=1001941</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/28/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/28/it&amp;diff=1001941"/>
		<updated>2023-05-27T12:47:23Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;$fieldset-&amp;gt;addAttribute(&amp;#039;addfieldprefix&amp;#039;, &amp;#039;Robbie\Component\Helloworld\Administrator\Field&amp;#039;);&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/27/it&amp;diff=1001940</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/27/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/27/it&amp;diff=1001940"/>
		<updated>2023-05-27T12:47:16Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;e anche in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; dove le associazioni vengono aggiunte dinamicamente al modulo per formare il campo di tipo &amp;lt;tt&amp;gt;modal_hellow...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;e anche in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; dove le associazioni vengono aggiunte dinamicamente al modulo per formare il campo di tipo &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; personalizzato:&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001939</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001939"/>
		<updated>2023-05-27T12:47:05Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;     addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;br /&gt;
&lt;br /&gt;
Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo namespace.&lt;br /&gt;
&lt;br /&gt;
Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altrimenti PHP cercherà di trovare nel tuo spazio dei nomi.&lt;br /&gt;
&lt;br /&gt;
Se utilizzi definizioni di campi o regole personalizzate nei tuoi file xml del modulo, devi indicare a PHP quale prefisso dello spazio dei nomi utilizzare per cercarli, ad esempio in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
    addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/26/it&amp;diff=1001938</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/26/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/26/it&amp;diff=1001938"/>
		<updated>2023-05-27T12:46:58Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;     addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001937</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001937"/>
		<updated>2023-05-27T12:46:36Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Se utilizzi definizioni di campi o regole personalizzate nei tuoi file xml del modulo, devi indicare a PHP quale prefisso dello spazio dei nomi utilizzare per cercarli, ad ese...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;br /&gt;
&lt;br /&gt;
Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo namespace.&lt;br /&gt;
&lt;br /&gt;
Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altrimenti PHP cercherà di trovare nel tuo spazio dei nomi.&lt;br /&gt;
&lt;br /&gt;
Se utilizzi definizioni di campi o regole personalizzate nei tuoi file xml del modulo, devi indicare a PHP quale prefisso dello spazio dei nomi utilizzare per cercarli, ad esempio in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/25/it&amp;diff=1001936</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/25/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/25/it&amp;diff=1001936"/>
		<updated>2023-05-27T12:46:33Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Se utilizzi definizioni di campi o regole personalizzate nei tuoi file xml del modulo, devi indicare a PHP quale prefisso dello spazio dei nomi utilizzare per cercarli, ad ese...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Se utilizzi definizioni di campi o regole personalizzate nei tuoi file xml del modulo, devi indicare a PHP quale prefisso dello spazio dei nomi utilizzare per cercarli, ad esempio in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001935</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001935"/>
		<updated>2023-05-27T12:46:14Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altri...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;br /&gt;
&lt;br /&gt;
Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo namespace.&lt;br /&gt;
&lt;br /&gt;
Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altrimenti PHP cercherà di trovare nel tuo spazio dei nomi.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/24/it&amp;diff=1001934</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/24/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/24/it&amp;diff=1001934"/>
		<updated>2023-05-27T12:46:09Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altri...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Inoltre, se usi una delle classi predefinite di PHP (ad es. &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) nel tuo codice, aggiungi una barra rovesciata prima di essa (ad es. &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), altrimenti PHP cercherà di trovare nel tuo spazio dei nomi.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001933</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001933"/>
		<updated>2023-05-27T12:45:44Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;br /&gt;
&lt;br /&gt;
Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo namespace.&lt;br /&gt;
&lt;br /&gt;
Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/23/it&amp;diff=1001932</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/23/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/23/it&amp;diff=1001932"/>
		<updated>2023-05-27T12:45:40Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Si noti in particolare come sono ora organizzati i file della classe &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/22/it&amp;diff=1001931</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/22/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/22/it&amp;diff=1001931"/>
		<updated>2023-05-27T12:45:32Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quindi il namespace che specifichi nei tuoi file di classe deve essere allineato con il percorso del tuo file PHP, sotto la cartella di base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; nel prefisso del tuo namespace.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001930</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001930"/>
		<updated>2023-05-27T12:44:41Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/21/it&amp;diff=1001929</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/21/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/21/it&amp;diff=1001929"/>
		<updated>2023-05-27T12:44:37Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In Joomla 4 genera il nome completo della classe che vuole trovare, quindi cerca di trovarlo nella posizione in cui la raccomandazione PSR-4 lo aspetterebbe.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001928</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001928"/>
		<updated>2023-05-27T12:44:25Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/20/it&amp;diff=1001927</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/20/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/20/it&amp;diff=1001927"/>
		<updated>2023-05-27T12:44:22Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quando Joomla 3 ha voluto chiamare le funzioni nel tuo componente, ha cercato determinati nomi di file in cartelle particolari e ha verificato che il nome della classe in quel file corrispondesse a quello previsto.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001926</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001926"/>
		<updated>2023-05-27T12:44:12Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&amp;#039;&amp;#039;&amp;#039;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/19/it&amp;diff=1001925</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/19/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/19/it&amp;diff=1001925"/>
		<updated>2023-05-27T12:44:12Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&amp;#039;&amp;#039;&amp;#039;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Nota che le lettere maiuscole sono importanti nei namespace, nei nomi delle classi e nei nomi dei percorsi!&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001924</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001924"/>
		<updated>2023-05-27T12:43:59Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in  components/com_helloworld/src/Model/CategoryModel.php&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/18/it&amp;diff=1001923</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/18/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/18/it&amp;diff=1001923"/>
		<updated>2023-05-27T12:43:56Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in  components/com_helloworld/src/Model/CategoryModel.php&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 components/com_helloworld/src/Model/CategoryModel.php&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001922</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001922"/>
		<updated>2023-05-27T12:43:43Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in  administrator/components/com_helloworld/src/Controller/DisplayController.php&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/17/it&amp;diff=1001921</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/17/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/17/it&amp;diff=1001921"/>
		<updated>2023-05-27T12:43:37Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in  administrator/components/com_helloworld/src/Controller/DisplayController.php&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; si troverà in&lt;br /&gt;
 administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001920</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001920"/>
		<updated>2023-05-27T12:43:14Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome del...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/16/it&amp;diff=1001919</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/16/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/16/it&amp;diff=1001919"/>
		<updated>2023-05-27T12:43:10Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome del...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quindi Joomla ora si aspetta che tutti i nomi delle classi vengano trovati in quelle directory di base, con il nome del file che corrisponde al nome della classe e il nome della classe completo che corrisponde al percorso, ad esempio&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001918</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001918"/>
		<updated>2023-05-27T12:43:08Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&amp;#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/15/it&amp;diff=1001917</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/15/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/15/it&amp;diff=1001917"/>
		<updated>2023-05-27T12:42:57Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&amp;#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – punterà a components/com_helloworld/src sull&#039;istanza live ed è associato a site/src nella nostra area di sviluppo.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001916</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001916"/>
		<updated>2023-05-27T12:42:48Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&amp;#039;istanza live ed è associato ad admin/src nella nostra area...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/14/it&amp;diff=1001915</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/14/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/14/it&amp;diff=1001915"/>
		<updated>2023-05-27T12:42:47Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&amp;#039;istanza live ed è associato ad admin/src nella nostra area...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – punterà ad administrator/components/com_helloworld/src sull&#039;istanza live ed è associato ad admin/src nella nostra area di sviluppo.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001914</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001914"/>
		<updated>2023-05-27T12:42:43Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/13/it&amp;diff=1001913</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/13/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/13/it&amp;diff=1001913"/>
		<updated>2023-05-27T12:42:40Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questo in realtà crea 2 prefissi dello spazio dei nomi, che puntano a cartelle specifiche nella nostra struttura di sviluppo helloworld e nella nostra istanza joomla live:&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001912</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001912"/>
		<updated>2023-05-27T12:42:32Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;(L&amp;#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/12/it&amp;diff=1001911</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/12/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/12/it&amp;diff=1001911"/>
		<updated>2023-05-27T12:42:31Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;(L&amp;#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;(L&#039;attributo &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; indica che si aspetterà che le classi si trovino nella sottocartella &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt;.)&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001910</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001910"/>
		<updated>2023-05-27T12:42:30Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/11/it&amp;diff=1001909</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/11/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/11/it&amp;diff=1001909"/>
		<updated>2023-05-27T12:42:23Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001908</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001908"/>
		<updated>2023-05-27T12:42:19Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&amp;#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpa...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/10/it&amp;diff=1001907</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/10/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/10/it&amp;diff=1001907"/>
		<updated>2023-05-27T12:42:13Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&amp;#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpa...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ora è previsto che anche le estensioni di Joomla utilizzino i NameSpace di base per l&#039;estensione definito nel suo file XML manifest.  I componenti di Joomla usano uno NameSpace della forma &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Nome componente&amp;gt;&amp;lt;/tt&amp;gt; es. &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, quindi seguendo questo schema ho dato una base al codice del tutorial spazio dei nomi di &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;.  Ecco la riga nel file manifest helloworld.xml:&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001906</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001906"/>
		<updated>2023-05-27T12:40:43Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;== NameSpace ==  ===NameSpace dei nomi dei componenti=== I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmen...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It is now expected that Joomla extensions use namespacing also, with the base namespace for the extension defined in its manifest XML file. Joomla components use a namespace of the form &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Component Name&amp;gt;&amp;lt;/tt&amp;gt; eg &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, so following that scheme I&#039;ve given the tutorial code a base namespace of &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;. Here&#039;s the line in the manifest helloworld.xml file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/9/it&amp;diff=1001905</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/9/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/9/it&amp;diff=1001905"/>
		<updated>2023-05-27T12:40:38Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;== NameSpace ==  ===NameSpace dei nomi dei componenti=== I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmen...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NameSpace ==&lt;br /&gt;
 ===NameSpace dei nomi dei componenti===&lt;br /&gt;
I NameSpace delle classi che utilizza la [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] è stato gradualmente introdotto durante le versioni di Joomla 3 e con Joomla 4 è praticamente tutto con NameSpace&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001904</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001904"/>
		<updated>2023-05-27T12:39:27Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiorn...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Namespacing ==&lt;br /&gt;
===Component Namespacing===&lt;br /&gt;
Namespacing of classes using the [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] was gradually introduced during Joomla 3 releases, and with Joomla 4 it is pretty much all namespaced.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It is now expected that Joomla extensions use namespacing also, with the base namespace for the extension defined in its manifest XML file. Joomla components use a namespace of the form &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Component Name&amp;gt;&amp;lt;/tt&amp;gt; eg &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, so following that scheme I&#039;ve given the tutorial code a base namespace of &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;. Here&#039;s the line in the manifest helloworld.xml file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/8/it&amp;diff=1001903</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/8/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/8/it&amp;diff=1001903"/>
		<updated>2023-05-27T12:39:26Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiorn...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questo passaggio non copre tutto ciò che è necessario per aggiornare un componente da Joomla 3 a Joomla 4, solo gli aspetti coperti dal codice del tutorial.  Se stai aggiornando il tuo componente Joomla 3, potresti trovare utile esaminare [[Potenziali problemi di compatibilità con le versioni precedenti in Joomla 4]].&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001902</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001902"/>
		<updated>2023-05-27T12:39:10Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;=== Ulteriori letture ===  Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simi...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This step doesn&#039;t cover everything required to update a component from Joomla 3 to Joomla 4, just the aspects covered by the tutorial code. If you&#039;re upgrading your own Joomla 3 component then you may find it helpful to look at [[Potential backward compatibility issues in Joomla 4]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Namespacing ==&lt;br /&gt;
===Component Namespacing===&lt;br /&gt;
Namespacing of classes using the [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] was gradually introduced during Joomla 3 releases, and with Joomla 4 it is pretty much all namespaced.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It is now expected that Joomla extensions use namespacing also, with the base namespace for the extension defined in its manifest XML file. Joomla components use a namespace of the form &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Component Name&amp;gt;&amp;lt;/tt&amp;gt; eg &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, so following that scheme I&#039;ve given the tutorial code a base namespace of &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;. Here&#039;s the line in the manifest helloworld.xml file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/7/it&amp;diff=1001901</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/7/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/7/it&amp;diff=1001901"/>
		<updated>2023-05-27T12:39:07Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;=== Ulteriori letture ===  Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simi...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Ulteriori letture ===&lt;br /&gt;
 Puoi trovare [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ qui] un tutorial per lo sviluppo dei componenti di Joomla 4, simile a questo Joomla 3, e alcuni eccellenti Joomla 4 è disponibile anche la documentazione [https://www.dionysopoulos.me/book.html qui].  Entrambi questi riferimenti includono descrizioni degli impatti di Joomla 4 sullo sviluppo di altri tipi di estensioni Joomla (plugin, moduli e modelli), che non sono trattati qui.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001900</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001900"/>
		<updated>2023-05-27T12:38:42Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
=== Further Reading ===&lt;br /&gt;
You can find [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ here] a tutorial for Joomla 4 component development, similar to this Joomla 3 one, and some excellent Joomla 4 documentation is also available [https://www.dionysopoulos.me/book.html here]. Both of these references include descriptions of Joomla 4 impacts on development of other types of Joomla extensions (plugins, modules and templates), which aren&#039;t covered here.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This step doesn&#039;t cover everything required to update a component from Joomla 3 to Joomla 4, just the aspects covered by the tutorial code. If you&#039;re upgrading your own Joomla 3 component then you may find it helpful to look at [[Potential backward compatibility issues in Joomla 4]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Namespacing ==&lt;br /&gt;
===Component Namespacing===&lt;br /&gt;
Namespacing of classes using the [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] was gradually introduced during Joomla 3 releases, and with Joomla 4 it is pretty much all namespaced.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It is now expected that Joomla extensions use namespacing also, with the base namespace for the extension defined in its manifest XML file. Joomla components use a namespace of the form &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Component Name&amp;gt;&amp;lt;/tt&amp;gt; eg &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, so following that scheme I&#039;ve given the tutorial code a base namespace of &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;. Here&#039;s the line in the manifest helloworld.xml file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/6/it&amp;diff=1001899</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/6/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/6/it&amp;diff=1001899"/>
		<updated>2023-05-27T12:38:41Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Se stai installando il codice del tutorial di Joomla 4 su una nuova istanza di Joomla, dovrai configurare la tua istanza per renderla multilingue e aggiungere le voci di menu nascoste di Ajax come descritto nel passaggio [[J3.x:Developing an MVC Component/ Utilizzo del filtro della lingua |Utilizzo del filtro della lingua]].  Assicurati inoltre che ogni record helloworld abbia una categoria valida.&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001898</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001898"/>
		<updated>2023-05-27T12:38:12Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poich...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository]. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you&#039;re installing the Joomla 4 tutorial code on a new Joomla instance then you will need to configure your instance to make it multilingual and add in the Ajax hidden menuitems as described in the step [[J3.x:Developing an MVC Component/Using the language filter facility|Using the language filter facility]]. Also ensure that every helloworld record has a valid category.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
=== Further Reading ===&lt;br /&gt;
You can find [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ here] a tutorial for Joomla 4 component development, similar to this Joomla 3 one, and some excellent Joomla 4 documentation is also available [https://www.dionysopoulos.me/book.html here]. Both of these references include descriptions of Joomla 4 impacts on development of other types of Joomla extensions (plugins, modules and templates), which aren&#039;t covered here.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This step doesn&#039;t cover everything required to update a component from Joomla 3 to Joomla 4, just the aspects covered by the tutorial code. If you&#039;re upgrading your own Joomla 3 component then you may find it helpful to look at [[Potential backward compatibility issues in Joomla 4]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Namespacing ==&lt;br /&gt;
===Component Namespacing===&lt;br /&gt;
Namespacing of classes using the [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] was gradually introduced during Joomla 3 releases, and with Joomla 4 it is pretty much all namespaced.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It is now expected that Joomla extensions use namespacing also, with the base namespace for the extension defined in its manifest XML file. Joomla components use a namespace of the form &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Component Name&amp;gt;&amp;lt;/tt&amp;gt; eg &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, so following that scheme I&#039;ve given the tutorial code a base namespace of &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;. Here&#039;s the line in the manifest helloworld.xml file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/5/it&amp;diff=1001897</id>
		<title>Translations:J3.x:Developing an MVC Component/Upgrading to Joomla4/5/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=Translations:J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/5/it&amp;diff=1001897"/>
		<updated>2023-05-27T12:38:11Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poich...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Il codice per questo passaggio è stato sviluppato seguendo ciascuno dei precedenti passaggi del tutorial e cercando di far funzionare ogni passaggio con Joomla 4.2.5.  Poiché Joomla 4 si sta ancora evolvendo abbastanza velocemente, è possibile che alcuni aspetti qui citati vengano modificati durante la vita di Joomla 4. Sentiti libero di correggere gli aspetti in questa pagina e creare richieste pull su [https://github.com/robbiejackson /Joomla-4-MVC-Tutorial Joomla 4 github repository].&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
	<entry>
		<id>https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001896</id>
		<title>J3.x:Developing an MVC Component/Upgrading to Joomla4/it</title>
		<link rel="alternate" type="text/html" href="https://docs.sandbox.joomla.org/index.php?title=J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4/it&amp;diff=1001896"/>
		<updated>2023-05-27T12:37:54Z</updated>

		<summary type="html">&lt;p&gt;Ing Pulizzi: Created page with &amp;quot;Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&amp;#039;esercitazione.  Invece puoi trovare il codice come...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;noinclude&amp;gt;&amp;lt;languages /&amp;gt;&amp;lt;/noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{:J3.1:Developing an MVC Component/it}}&lt;br /&gt;
Questo passaggio copre ciò che è coinvolto nell&#039;aggiornamento del codice del tutorial per allinearlo con la versione 4 di Joomla.&lt;br /&gt;
&lt;br /&gt;
== Introduzione ==&lt;br /&gt;
 Questa pagina descrive i principali aspetti relativi allo sviluppo dei componenti che sono stati introdotti in Joomla 4 e descrive in dettaglio cosa è stato modificato nel codice del tutorial per allinearsi con v4. &lt;br /&gt;
&lt;br /&gt;
Non è pratico dettagliare tutte le modifiche al codice sulla pagina Web come è stato fatto per i passaggi precedenti dell&#039;esercitazione.  Invece puoi trovare il codice come repository github su [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 Tutorial code], e puoi confrontarlo con il codice del passaggio precedente del tutorial (Adding Custom Fields) su [https://github.com/robbiejackson/Joomla-3-MVC-Tutorial Joomla 3 MVC code].  Il codice di Joomla 4 replica tutte le funzionalità del codice di Joomla 3, con l&#039;eccezione dell&#039;implementazione dell&#039;icona del piccolo pinguino introdotta in [[S:MyLanguage/J3.2:Developing an MVC Component/Adding decorations to the backend|Aggiunta di decorazioni al backend]] (che non è così rilevante data la modifica dell&#039;interfaccia utente in Joomla 4 Administrator) e l&#039;uso di un plug-in CAPTCHA ([[J3.x:Developing an MVC Component/Adding a frontend form|Adding a frontend form]] ).  Probabilmente troverai utile avere a portata di mano questo codice Joomla 4 a cui fare riferimento mentre leggi questa pagina. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code for this step has been developed by going through each of the previous tutorial steps and trying to get each step working under Joomla 4.2.5. As Joomla 4 is still evolving quite fast it may be that certain aspects cited here get modified during the lifetime of Joomla 4. Please feel free to correct aspects on this page and create pull requests on the [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial Joomla 4 github repository].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you&#039;re installing the Joomla 4 tutorial code on a new Joomla instance then you will need to configure your instance to make it multilingual and add in the Ajax hidden menuitems as described in the step [[J3.x:Developing an MVC Component/Using the language filter facility|Using the language filter facility]]. Also ensure that every helloworld record has a valid category.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
=== Further Reading ===&lt;br /&gt;
You can find [https://blog.astrid-guenther.de/en/der-weg-zu-joomla4-erweiterungen/ here] a tutorial for Joomla 4 component development, similar to this Joomla 3 one, and some excellent Joomla 4 documentation is also available [https://www.dionysopoulos.me/book.html here]. Both of these references include descriptions of Joomla 4 impacts on development of other types of Joomla extensions (plugins, modules and templates), which aren&#039;t covered here.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This step doesn&#039;t cover everything required to update a component from Joomla 3 to Joomla 4, just the aspects covered by the tutorial code. If you&#039;re upgrading your own Joomla 3 component then you may find it helpful to look at [[Potential backward compatibility issues in Joomla 4]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Namespacing ==&lt;br /&gt;
===Component Namespacing===&lt;br /&gt;
Namespacing of classes using the [https://www.php-fig.org/psr/psr-4/ PSR-4 recommendation] was gradually introduced during Joomla 3 releases, and with Joomla 4 it is pretty much all namespaced.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It is now expected that Joomla extensions use namespacing also, with the base namespace for the extension defined in its manifest XML file. Joomla components use a namespace of the form &amp;lt;tt&amp;gt;Joomla\Component\&amp;lt;Component Name&amp;gt;&amp;lt;/tt&amp;gt; eg &amp;lt;tt&amp;gt;Joomla\Component\Content&amp;lt;/tt&amp;gt;, so following that scheme I&#039;ve given the tutorial code a base namespace of &amp;lt;tt&amp;gt;Robbie\Component\Helloworld&amp;lt;/tt&amp;gt;. Here&#039;s the line in the manifest helloworld.xml file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace path=&amp;quot;src&amp;quot;&amp;gt;Robbie\Component\Helloworld&amp;lt;/namespace&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(The &amp;lt;tt&amp;gt;path=&amp;quot;src&amp;quot;&amp;lt;/tt&amp;gt; attribute means that it will expect the classes to be under the &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; subfolder.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This actually creates 2 namespace prefixes, pointing to specific folders in our helloworld development structure and in our live joomla instance:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator&amp;lt;/tt&amp;gt; – will point to administrator/components/com_helloworld/src on the live instance and is associated with admin/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site&amp;lt;/tt&amp;gt; – will point to components/com_helloworld/src on the live instance, and is associated with site/src in our development area.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So Joomla now expects all classes names will be found under those base directories, with file name matching the class name, and the fully qualified classname matching the path eg&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Administrator\Controller\DisplayController&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
administrator/components/com_helloworld/src/Controller/DisplayController.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Robbie\Component\Helloworld\Site\Model\CategoryModel&amp;lt;/tt&amp;gt; will be found in&lt;br /&gt;
components/com_helloworld/src/Model/CategoryModel.php&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Note that capitalization is important in namespaces, names of classes and path names!&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla 3 wanted to call functions in your component it looked for certain file names in particular folders, and checked that the name of the class in that file matched what it expected.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it generates the fully qualified name of the class it wants to find, and then looks to find it in the location where the PSR-4 recommendation would expect it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Hence the namespace you specify in your class files must align with the file path to your PHP file, below the base &amp;lt;tt&amp;gt;src&amp;lt;/tt&amp;gt; folder at your namespace prefix.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note in particular how the &amp;lt;tt&amp;gt;View&amp;lt;/tt&amp;gt; class files are now organised.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Also if you use one of the PHP predefined classes (eg &amp;lt;tt&amp;gt;Exception&amp;lt;/tt&amp;gt;) in your code, then add a backslash before it (eg &amp;lt;tt&amp;gt;\Exception&amp;lt;/tt&amp;gt;), otherwise PHP will try and find it in your namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you use custom Field or Rule definitions in your form xml files then you have to indicate to PHP which namespace prefix to use to look for them, eg in &amp;lt;tt&amp;gt;site/forms/add-form.xml&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
addruleprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Rule&amp;quot;&lt;br /&gt;
    addfieldprefix=&amp;quot;Robbie\Component\Helloworld\Administrator\Field&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and also in &amp;lt;tt&amp;gt;admin/src/Model/HelloworldModel::preprocessForm&amp;lt;/tt&amp;gt; where the associations are added into the form dynamically to form the custom &amp;lt;tt&amp;gt;modal_helloworld&amp;lt;/tt&amp;gt; type field:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$fieldset-&amp;gt;addAttribute(&#039;addfieldprefix&#039;, &#039;Robbie\Component\Helloworld\Administrator\Field&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Class Autoloading===&lt;br /&gt;
Joomla uses the PHP mechanism for [https://www.php.net/manual/en/language.oop5.autoload.php Autoloading Classes] and on startup registers a number of autoloaders – functions which get called when PHP can&#039;t find a given class. In particular the Joomla PSR-4 autoloader function (in &amp;lt;tt&amp;gt;libraries/loader.php&amp;lt;/tt&amp;gt;) is responsible for finding classes of Joomla extensions whose code is in source files which are organised according to the PSR-4 recommendation. (Joomla library classes are autoloaded using a different autoloader – see &amp;lt;tt&amp;gt;libraries/vendor/composer/autoload_static.php&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You can see the namespace prefixes of extensions on the Joomla instance by looking at &amp;lt;tt&amp;gt;administrator/cache/autoload_psr4.php&amp;lt;/tt&amp;gt;. (These namespace strings have double backslashes, but in PHP they&#039;re the [https://stackoverflow.com/questions/25459197/single-or-double-slash-when-using-php-namespace same strings as those with single backslashes]). This is generated by Joomla looking through the component, module and plugin directories to find each extension&#039;s manifest file, and then processing these xml files to extract the &amp;lt;tt&amp;gt;&amp;lt;namespace&amp;gt;&amp;lt;/tt&amp;gt; element – quite a lot of work, which is why it&#039;s cached I guess!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider what happens when Joomla wants our admin HelloworldController class. It might have something like&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$classname = &#039;Robbie\Component\Helloworld\Administrator\Controller\HelloworldController&#039;&lt;br /&gt;
    if (!class_exists($classname)) { …&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Assuming PHP doesn&#039;t already know about this class, the &amp;lt;tt&amp;gt;class_exists&amp;lt;/tt&amp;gt; function will result in the classname being passed to the registered autoload function(s). The PSR-4 autoloader will then:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# go through its array of namespaces to try and match &amp;lt;tt&amp;gt;$classname&amp;lt;/tt&amp;gt; from the start of the string. &lt;br /&gt;
# find &#039;Robbie\Component\Helloworld\Administrator&#039; as a match&lt;br /&gt;
# see that this maps to &amp;quot;administrator/components/com_helloworld/src&amp;quot;&lt;br /&gt;
# extract the remainder of the classname: &#039;Controller\HelloworldController&#039;&lt;br /&gt;
# treat this as the path down to the class file&lt;br /&gt;
# and so look for &amp;quot;administrator/components/com_helloworld/src/Controller/HelloworldController.php&amp;quot;&lt;br /&gt;
# check that in this file there&#039;s actually a class with that namespace + class name.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So in this way Joomla can go from a fully qualified class name to find the source code for that class. This makes it easier for us too when the core Joomla code is looking for one of our classes. We still need to know what class it&#039;s looking for, but once we know that, we know what we should call our class and where we should save the source code for it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Joomla Library classes===&lt;br /&gt;
Originally Joomla&#039;s core classes (beginning with a capital J) were global classes. Over the Joomla 3 versions and into Joomla 4 these migrated to their namespaced equivalents, but the original global classnames were still available as Joomla registered them as aliases (in the &amp;lt;tt&amp;gt;libraries/classmap.php&amp;lt;/tt&amp;gt; file).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In a Joomla 4 extension you can still use these global classnames, except that in a namespaced file you&#039;d have to prefix the name with a backslash to indicate a global class rather than one in your namespace (eg &amp;lt;tt&amp;gt;\JFactory&amp;lt;/tt&amp;gt; instead of &amp;lt;tt&amp;gt;JFactory&amp;lt;/tt&amp;gt;).&lt;br /&gt;
However it&#039;s pretty definite that the aliases will disappear at some stage, so the upgrade to Joomla 4 seems an appropriate opportunity to replace all your component&#039;s calls to the global JSomething classes to the namespaced equivalents. This involves adding the appropriate &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statements, and all this has been done in the tutorial code. A useful mapping between the two can be found [https://github.com/nikosdion/joomlatypehints/blob/main/JoomlaObsoleteClasses.md here], where the new qualified classname can be copied and pasted into a &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement in your PHP file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
With reference to the [https://api.joomla.org/ Joomla API Documentation] there are 2 Joomla library namespaces:&lt;br /&gt;
* Joomla CMS classes – have namespaces &amp;lt;tt&amp;gt;Joomla\CMS\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/src/Something&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Joomla Framework classes – have namespaces &amp;lt;tt&amp;gt;Joomla\Something&amp;lt;/tt&amp;gt; – are found under &amp;lt;tt&amp;gt;libraries/vendor/joomla/something/src&amp;lt;/tt&amp;gt;&lt;br /&gt;
So a big advantage of namespacing is that you can immediately determine from the fully qualified class name in a PHP &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement where the source for that class exists in the &amp;lt;tt&amp;gt;libraries&amp;lt;/tt&amp;gt; directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
On the other hand class names which aren&#039;t fully qualified don&#039;t have to be unique, eg &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/Extension/Service/Provider/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
* occurs as &amp;lt;tt&amp;gt;Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;&lt;br /&gt;
so sometimes you have to be careful to examine the &amp;lt;tt&amp;gt;use&amp;lt;/tt&amp;gt; statement to identify the right class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly our FormModel class in &amp;lt;tt&amp;gt;site/src/Model/FormModel.php&amp;lt;/tt&amp;gt; can have the same FormModel classname as the Joomla FormModel in &amp;lt;tt&amp;gt;libraries/src/MVC/Model/FormModel.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The API documentation gives the methods available in each of the [https://api.joomla.org/cms-4/namespaces/joomla.html Joomla CMS] and [https://api.joomla.org/framework-2/namespaces/joomla.html Framework] classes, but just be aware that a Joomla CMS class may extend a Framework class, and in this case some methods may not be visible under the Joomla CMS documentation.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;$app-&amp;gt;setHeader()&amp;lt;/tt&amp;gt; which is used to set the HTTP response code is not listed under the [https://api.joomla.org/cms-4/classes/Joomla-CMS-Application-CMSApplication.html CMS Application class API], but is available as a method because it inherits from the Framework class [https://api.joomla.org/framework-2/classes/Joomla-Application-AbstractWebApplication.html AbstractWebApplication].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Vendor Namespaces===&lt;br /&gt;
These are also in &amp;lt;tt&amp;gt;libraries/vendor&amp;lt;/tt&amp;gt;, eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Psr\Container\ContainerInterface;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
refers to &amp;lt;tt&amp;gt;libraries/vendor/psr/Container/src/ContainerInterface.php&amp;lt;/tt&amp;gt;. However there are few of these in the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other File Rearrangements===&lt;br /&gt;
With all of the namespaced classes moving under the src directories, the &amp;lt;tt&amp;gt;tmpl&amp;lt;/tt&amp;gt; layout files and &amp;lt;tt&amp;gt;form&amp;lt;/tt&amp;gt; xml files have been moved out into their own directories.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Extension and Dispatcher classes ==&lt;br /&gt;
===Extension===&lt;br /&gt;
In Joomla 3 the point where the Joomla core handed over to your component code was when it ran your &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code; if it was the frontend it ran your site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code, or if was the backend it ran your admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; code.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the entry point into your component code is your Extension class, both for site and admin, found in &amp;lt;tt&amp;gt;admin/src/Extension/HelloworldComponent.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When the Joomla core application wants to start executing the component code it creates an instance of &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt;, just to get a handle on the component code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Similarly (as described below) other Joomla classes such as Router or Categories need to call certain Helloworld methods (eg custom router functions). In Joomla 3 these methods were written in certain Helper files etc. In Joomla 4 the principle is that the component creates an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; Extension class, and calls the required methods on that instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This Extension class isn&#039;t anything like a big container class for the component, it&#039;s more like a glue class, providing a way in to the Helloworld component, enabling the Joomla core and other components call the methods which they want to call.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla core wants to execute the component code, the key method it is looking for in your &amp;lt;tt&amp;gt;Extension&amp;lt;/tt&amp;gt; instance is &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt;, and it expects to get back a &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance. The &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; extends &amp;lt;tt&amp;gt;MVCComponent&amp;lt;/tt&amp;gt;, which in turn extends &amp;lt;tt&amp;gt;Component&amp;lt;/tt&amp;gt;, and it is this class which defines &amp;lt;tt&amp;gt;getDispatcher&amp;lt;/tt&amp;gt; for us.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Dispatcher===&lt;br /&gt;
When Joomla wants to run the Hello World component, it gets the &amp;lt;tt&amp;gt;Dispatcher&amp;lt;/tt&amp;gt; instance as described above and then calls the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; method on it. It is this &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; function which replaces the functionality in the admin and site &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s look at the main lines of code in our Joomla 3 admin &amp;lt;tt&amp;gt;helloworld.php&amp;lt;/tt&amp;gt; file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;site/views/form/view.html.php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (!JFactory::getUser()-&amp;gt;authorise(&#039;core.manage&#039;, &#039;com_helloworld&#039;))&lt;br /&gt;
{&lt;br /&gt;
	throw new Exception(JText::_(&#039;JERROR_ALERTNOAUTHOR&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Get an instance of the controller&lt;br /&gt;
$controller = JControllerLegacy::getInstance(&#039;HelloWorld&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Execute the Request task method&lt;br /&gt;
$input = JFactory::getApplication()-&amp;gt;input;&lt;br /&gt;
$controller-&amp;gt;execute($input-&amp;gt;getCmd(&#039;task&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
// Redirect if set by the controller&lt;br /&gt;
$controller-&amp;gt;redirect();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
* performs some permissions checks&lt;br /&gt;
* instantiates the appropriate Helloworld controller&lt;br /&gt;
* executes the appropriate method in that controller&lt;br /&gt;
* implements any redirect set by the controller&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
See [[Model-View-Controller]] for further details of how this works in Joomla 3. The second and third steps used the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter within the URL query to determine the correct controller class to instantiate and method to call. If no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter was present then it instantiated the controller in &amp;lt;tt&amp;gt;controller.php&amp;lt;/tt&amp;gt; and called the &amp;lt;tt&amp;gt;display&amp;lt;/tt&amp;gt; method. Otherwise it instantiated one of the controllers in the &amp;lt;tt&amp;gt;controllers&amp;lt;/tt&amp;gt; subfolder (eg &amp;lt;tt&amp;gt;controllers/helloworld.php&amp;lt;/tt&amp;gt;) and called the appropriate method on it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;ComponentDispatcher::dispatch&amp;lt;/tt&amp;gt; method (in &amp;lt;tt&amp;gt;libraries/src/Dispatcher/ComponentDispatcher.php&amp;lt;/tt&amp;gt;) now provides this functionality, but in a nicer way. After checking the permissions it uses the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; by considering its parts as &amp;lt;tt&amp;gt;&amp;lt;controller type&amp;gt;.&amp;lt;method&amp;gt;&amp;lt;/tt&amp;gt; (taking &#039;display&#039; as default if either part is missing). It will then pass control to&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* an instance of the class &amp;lt;Controller type&amp;gt;Controller&lt;br /&gt;
* calling the function &amp;lt;method&amp;gt;&lt;br /&gt;
* using the admin or site controller, as appropriate&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In this way the naming of the controllers is consistent - we have DisplayController, HelloworldController and HelloworldsController, all in the same folder.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Dispatcher class can thus be considered as providing some &#039;routing - execution&#039; functionality, enabling us to find the right controller and function within that controller, and it is cleaner to have this in a separate class rather than in the &amp;lt;tt&amp;gt;JControllerLegacy&amp;lt;/tt&amp;gt; class as it was in Joomla 3.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Since the Hello World tutorial uses the standard Joomla pattern for selecting the class and method based on the &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; and has the same permissions checks, we can use the &amp;lt;tt&amp;gt;dispatch&amp;lt;/tt&amp;gt; code as it stands in &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt;, and don&#039;t need to define a special class of our own.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Factory classes ==&lt;br /&gt;
In Joomla 3 many classes had static &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods which returned an instance of that class, configured with the parameters passed to &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; methods have been deprecated in favour of using Factory classes. The preferred mechanism is now to&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* get an instance of the appropriate Factory class (how we do that is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below)&lt;br /&gt;
* call the &amp;lt;tt&amp;gt;createSomething()&amp;lt;/tt&amp;gt; method of the Factory class with relevant parameter values to generate an instance of the Something class.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===MVC Factory===&lt;br /&gt;
In this section the &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; class refers to the one in &amp;lt;tt&amp;gt;libraries/src/MVC/Factory/MVCFactory.php&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory class will instantiate Controller, View, Model and Table instances on our behalf, and it does this by generating the classname of the class and then calling &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The way it works is as follows:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
# Each component gets an individual MVCFactory instance which is constructed passing the component&#039;s namespace as a parameter (so in our case &#039;Robbie\Component\Helloworld&#039;). (How this MVCFactory instance is created is covered in the [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#services.2Fprovider.php|services/provider.php section]] below).&lt;br /&gt;
# The MVCFactory createController / createView / createModel / createTable function is then called, passing the name of the Controller / Model / View / Table and the prefix (which specifies whether the administrator or site class is required).&lt;br /&gt;
# The create function forms the classname from this data and calls &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVCFactory create functions just form the classname from the parameters they&#039;re passed. The intelligence for working out what name and prefix should be used to form the appropriate classes for an incoming HTTP request is&lt;br /&gt;
* in the dispatcher code for defining the controller to use&lt;br /&gt;
* in the controller for the view and model&lt;br /&gt;
* in the model for the table&lt;br /&gt;
and, for example, the names of the classes created for a request with URL query &amp;lt;tt&amp;gt;?option=com_helloworld&amp;amp;view=viewname&amp;lt;/tt&amp;gt; and no &amp;lt;tt&amp;gt;task&amp;lt;/tt&amp;gt; parameter will be&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;namespace&amp;gt;\Controller\DisplayController&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\View\Viewname\HtmlView&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Model\ViewnameModel&lt;br /&gt;
    &amp;lt;namespace&amp;gt;\Table\ViewnameTable&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you need an alternative name then you can override the appropriate getView, getModel or getTable function – as for example was done in the [[J3.x:Developing an MVC Component/Adding Custom Fields#Front-end_Form|Adding Custom Fields step, frontend Form section]].&lt;br /&gt;
&amp;lt;/div&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So from the outside this is pretty much the same as in Joomla 3. However, note that the &amp;lt;tt&amp;gt;$prefix&amp;lt;/tt&amp;gt; parameter in calls to &amp;lt;tt&amp;gt;getModel&amp;lt;/tt&amp;gt; etc is subtly different&lt;br /&gt;
* in Joomla 3 this referred to a prefix to be applied to the classname – in the tutorial code we used &#039;HelloWorldTable&#039; as the prefix part of the &#039;HelloWorldTableHelloWorld&#039; classname.&lt;br /&gt;
* in Joomla 4 this refers to a prefix higher up the classname path, and should be set to either &#039;Site&#039; or &#039;Administrator&#039; (the capital letter at the start is optional), depending on whether you want the class under &#039;Robbie\Component\Helloworld\Site&#039; or &#039;Robbie\Component\Helloworld\Administrator&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The MVC Factory class is now the Joomla recommended way to create the controller, view, model and table classes, by using the eg &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; method, and the use of &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; for these classes is now deprecated. However, the use of these functions is restricted:&lt;br /&gt;
* in the controller class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getView($viewname, $viewtype, $prefix, $config)&amp;lt;/tt&amp;gt; to create a view and &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname, $prefix, $config)&amp;lt;/tt&amp;gt; to create a model.&lt;br /&gt;
* in the view class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getModel($modelname)&amp;lt;/tt&amp;gt;, but only for models which the controller has previously defined using &amp;lt;tt&amp;gt;$view-&amp;gt;setModel($modelname, $default)&amp;lt;/tt&amp;gt;. It doesn&#039;t create a new model instance. &lt;br /&gt;
* in the model class you can call &amp;lt;tt&amp;gt;$this-&amp;gt;getTable($tableclass, $prefix, $options)&amp;lt;/tt&amp;gt; to create a table instance. Controllers and views can access the table classes in this way, by going via a model. &lt;br /&gt;
These restrictions do have an impact on moving away from using &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt;, and indeed in Joomla 4.2.6 you will still find several &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Other Factory Classes===&lt;br /&gt;
Several other Factory classes have been introduced in Joomla 4, enabling you to get instances of core classes such as Form, User, CacheController, etc, usually by calling a createSomething function on the Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Associated with the Factory class is a FactoryInterface, a PHP Interface which specifies the key functions which the Factory class must implement. For example, with &amp;lt;tt&amp;gt;libraries/src/Categories&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
* CategoryFactoryInterface – which specifies the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function&lt;br /&gt;
* CategoryFactory implements CategoryFactoryInterface – which provides the &amp;lt;tt&amp;gt;createCategory&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Dependency Injection ==&lt;br /&gt;
===Overview===&lt;br /&gt;
The DI container is one of the significant new additions to Joomla 4. It&#039;s basically a repository of key-value pairs where:&lt;br /&gt;
* the key is a string which is the name of a class or interface&lt;br /&gt;
* the value is an instance of the relevant class, or a function that returns an instance of that class. &lt;br /&gt;
You put things into the container using &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; passing:&lt;br /&gt;
* the class name or interface name&lt;br /&gt;
* a function which returns an instance of the class (or an instance of the class)&lt;br /&gt;
* a boolean defining whether the class instance may be shared or not&lt;br /&gt;
* a boolean defining whether this entry into the DI container is protected or not (an error will be raised if you try to overwrite a protected entry by calling &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; again using the same key).&lt;br /&gt;
The function &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; is basically the same as &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; with the &amp;lt;tt&amp;gt;shared&amp;lt;/tt&amp;gt; boolean set to true.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You get things out of the container by calling &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing the key of the resource you want. The container will &lt;br /&gt;
* find the key in the container&lt;br /&gt;
* if the value isn&#039;t already a class instance, then it will run the associated function to generate an instance of the class&lt;br /&gt;
* if the resource is shared, it will store the class instance, so that on subsequent invocations of &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; it can just return the instance&lt;br /&gt;
* return the class instance to you&lt;br /&gt;
You can also define aliases for each key in the container, which means that you call &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; passing either the key or an alias of the key.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The DI container is initialised in &amp;lt;tt&amp;gt;library/src/Factory.php createContainer()&amp;lt;/tt&amp;gt; which results in the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function being called in each of the class files in &amp;lt;tt&amp;gt;libraries/src/Service/Provider&amp;lt;/tt&amp;gt;. By looking through those files you can see what gets put into the DI container upon initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===JConfig Example===&lt;br /&gt;
Let&#039;s consider the example of JConfig which holds the system global configuration. If you look inside &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; then you&#039;ll see the &amp;lt;tt&amp;gt;register()&amp;lt;/tt&amp;gt; function and that it stores in the DI container a resource with:&lt;br /&gt;
* key = &#039;JConfig&#039;&lt;br /&gt;
* value = an anonymous function - which loads what&#039;s in &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a &amp;lt;tt&amp;gt;Registry&amp;lt;/tt&amp;gt; object, and returns it&lt;br /&gt;
* shared flag = true (because the &amp;lt;tt&amp;gt;share()&amp;lt;/tt&amp;gt; function is used)&lt;br /&gt;
* protected flag = true&lt;br /&gt;
Then when you do&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$config = $container-&amp;gt;get(&#039;JConfig&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will run the anonymous function and return the Registry object to you. As the &#039;shared&#039; boolean is set it will also store a copy of the class instance locally in the container to be returned on subsequent calls of &amp;lt;tt&amp;gt;get(&#039;JConfig&#039;)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Justification===&lt;br /&gt;
What&#039;s the point of all this?&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The advantage of dependency injection is that it allows classes to be easily mocked for testing. The file &amp;lt;tt&amp;gt;libraries/src/Service/Provider/Config.php&amp;lt;/tt&amp;gt; can be replaced to return to a DI container &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; call a mock class instead of the usual &amp;lt;tt&amp;gt;JConfig&amp;lt;/tt&amp;gt;. This is in comparison to Joomla 3 where &amp;lt;tt&amp;gt;Factory::getConfig()&amp;lt;/tt&amp;gt; code directly reads the &amp;lt;tt&amp;gt;configuration.php&amp;lt;/tt&amp;gt; into a Registry structure and returns it – which makes it harder to mock.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The [https://api.joomla.org/cms-4/classes/Joomla-CMS-Factory.html Factory API] has several functions which are marked as deprecated with advice to get the object from the DI container instead.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Several of the other Factory classes (eg Form, Language, Menu, User) are in the DI container – so that we can get an instance of them via eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Factory::getContainer()-&amp;gt;get(&#039;Joomla\CMS\Toolbar\ToolbarFactoryInterface&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to get a Toolbar instance. However, this only works for singleton classes which aren&#039;t specific to the needs of a particular extension. We&#039;ll see shortly how to make it work for class instances which need to be specific to a component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As indicated above, Joomla is moving away from using the class static &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; functions. We can see now that this is not only because it&#039;s more pure from an object oriented perspective. But also creating class instances from the DI container, or from Factory objects which are obtained from the DI container, builds in the dependency injection which allows classes to be more easily mocked, and hence more easily tested.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==services/provider.php==&lt;br /&gt;
We&#039;re now finally in a good position to understand what&#039;s happening in our services/provider.php file, and we&#039;ll explore this by walking through what happens whenever this line in libraries/src/Component/ComponentHelper.php &amp;lt;tt&amp;gt;renderComponent&amp;lt;/tt&amp;gt; is run:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is run whenever Joomla has worked out which component is to be run on the requested web page, and it wants to run that component to capture its output.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 1 Create Child DI Container===&lt;br /&gt;
Joomla first creates another DI container (initially empty) just for this component, and links it to the main DI container via a parent field in the child DI container structure.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Now whenever &amp;lt;tt&amp;gt;set()&amp;lt;/tt&amp;gt; is called on this DI container the key-value pair is inserted into the child container. Whenever &amp;lt;tt&amp;gt;get()&amp;lt;/tt&amp;gt; is called on it, the resource is obtained from the child container, but if it&#039;s not found there then the parent container is searched also.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 2 Run register() in provider.php===&lt;br /&gt;
Next we encounter these lines (in &amp;lt;tt&amp;gt;libraries/src/Extension/ExtensionManagerTrait.php&amp;lt;/tt&amp;gt;), where &amp;lt;tt&amp;gt;$path&amp;lt;/tt&amp;gt; contains the path of our helloworld admin/services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$provider = require_once $path;&lt;br /&gt;
    // Check if the extension supports the service provider interface&lt;br /&gt;
    if ($provider instanceof ServiceProviderInterface) {&lt;br /&gt;
        $provider-&amp;gt;register($container);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here we see 3 things:&lt;br /&gt;
# our provider.php should return some object (so that &amp;lt;tt&amp;gt;$provider&amp;lt;/tt&amp;gt; gets set to something)&lt;br /&gt;
# what is returned should implement ServiceProviderInterface (you can see in &amp;lt;tt&amp;gt;libraries/vendor/joomla/di/src/ServiceProviderInterface.php&amp;lt;/tt&amp;gt; what is expected)&lt;br /&gt;
# the code then runs the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function on that object, passing as a parameter the child DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Let&#039;s consider a minimal version of our provider.php file. This would actually support steps in the Joomla 3 tutorial up to and including the [[J3.x:Developing an MVC Component/Adding AJAX|Adding Ajax step]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
        &lt;br /&gt;
        public function register(Container $container): void &lt;br /&gt;
        {&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
            $container-&amp;gt;set(&lt;br /&gt;
                ComponentInterface::class,&lt;br /&gt;
                function (Container $container) {&lt;br /&gt;
                    $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
                    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
                    return $component;&lt;br /&gt;
                }&lt;br /&gt;
            );&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As you can see from the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
return new class implements ServiceProviderInterface {&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
this file does indeed return something – it returns an instance of an anonymous class, one that implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function in the class, we also need to explicity state that the class implements &amp;lt;tt&amp;gt;ServiceProviderInterface&amp;lt;/tt&amp;gt;. This now happens in several places in Joomla, so if you&#039;re debugging your component and wondering why a function you expect to be called isn&#039;t being called, then check to make sure that you don&#039;t have to explicitly add the appropriate &amp;lt;tt&amp;gt;implements &amp;lt;Interface&amp;gt;&amp;lt;/tt&amp;gt; clause to your class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Next we look at the 3 lines in the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3a Registering our MVC Factory===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here our &amp;lt;tt&amp;gt;MVCFactory&amp;lt;/tt&amp;gt; refers to &amp;lt;tt&amp;gt;Joomla\CMS\Extension\Service\Provider\MVCFactory&amp;lt;/tt&amp;gt; in libraries/src/Extension/Service/Provider/MVCFactory.php, and you should have a look at this file. This is a file similar to our provider.php file, but it&#039;s a named class, and it doesn&#039;t return anything. When we do:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
new MVCFactory(&#039;\\Robbie\\Component\\Helloworld&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it creates an instance of this class, and in the constructor it stores locally in &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt; our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;registerServiceProvider&amp;lt;/tt&amp;gt; function then calls the &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; function of this instance, which runs (in its minimalist form):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        MVCFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
            return $factory;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So what gets entered into our child DI container is a key-value pair with:&lt;br /&gt;
* key =  MVCFactoryInterface::class (this is just a shorthand form to obtain a string of the fully qualified name – ie &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039;)&lt;br /&gt;
* value = a function which returns an instance of &amp;lt;tt&amp;gt;\Joomla\CMS\MVC\Factory\MVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
This is our MVCFactory class which generates our Controllers, Views, Models and Tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Notice that we&#039;re passing our namespace as a parameter &amp;lt;tt&amp;gt;$this-&amp;gt;namespace&amp;lt;/tt&amp;gt;. Because this function is a closure, this variable will still be available when we run this function later, and when the MVCFactory class is instantiated the namespace will be passed into the constructor, stored locally, and then subsequently used to form the fully qualified names of our Controllers, View, etc. So this is how we get instantiated the MVCFactory class which is specific to our component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3b Registering the Dispatcher Factory===&lt;br /&gt;
Careful: ComponentDispatcherFactory refers to two different classes here!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new ComponentDispatcherFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This ComponentDispatcherFactory is Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory in libraries/src/Extension/Service/Provider/ComponentDispatcherFactory.php. Similar to the above, the ComponentDispatcherFactory service provider class stores locally our namespace, and then when &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; is called it executes:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentDispatcherFactoryInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            return new \Joomla\CMS\Dispatcher\ComponentDispatcherFactory($this-&amp;gt;namespace,$container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so a second entry is added to the child DI container with:&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class&lt;br /&gt;
* value = a function which returns an instance of the ComponentDispatcherFactory (the other ComponentDispatcherFactory class!), where the class constructor will be passed the namespace (&#039;\\Robbie\\Component\\Helloworld&#039;) and an MVCFactory instance, retrieved from the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that the code&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;get(MVCFactoryInterface::class)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
will get from the container an entry with key = &#039;Joomla\CMS\MVC\Factory\MVCFactoryInterface&#039; – which is what we entered into the container in step 3a – and will run the function associated with this key, and then return the object which this function returns. This returned object will be an instance of &#039;\Joomla\CMS\MVC\Factory\MVCFactory&#039;, constructed using our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3c Including the Extension===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(&lt;br /&gt;
        ComponentInterface::class,&lt;br /&gt;
        function (Container $container) {&lt;br /&gt;
            $component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
            $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
            return $component;&lt;br /&gt;
        }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will put into the child DI container a key-value pair with&lt;br /&gt;
* key = ComponentInterface::class &lt;br /&gt;
* value = the function which will create an instance of our &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; (ie our Extension class), and pass into the constructor an instance of the ComponentDispatcherFactory class, retrieving what was entered into the child DI container in Step 3b. &lt;br /&gt;
It will call &amp;lt;tt&amp;gt;$container-&amp;gt;get(MVCFactoryInterface::class)&amp;lt;/tt&amp;gt;, getting an MVC Factory instance from what was entered into the DI container in Step 3a.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It will then associate our component with this MVC Factory instance via the &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call. Significantly this will then allow our component to access this instance later, via a call to &amp;lt;tt&amp;gt;getMVCFactory&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 3 Summary===&lt;br /&gt;
We have now got 3 entries in our child DI container, keyed by &lt;br /&gt;
* key = MVCFactoryInterface::class, value is a function returning an MVCFactory instance&lt;br /&gt;
* key = ComponentDispatcherFactoryInterface::class, value is a function returning a ComponentDispatcherFactory instance&lt;br /&gt;
* key = ComponentInterface::class, value is a function returning our HelloworldComponent, an instance of our Extension class. &lt;br /&gt;
The important aspect is that these entries are all aware of our namespace &#039;\Robbie\Component\Helloworld&#039; and will return instances of these classes which are specific to our Helloworld component.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 4 Retrieving from the DI Container===&lt;br /&gt;
Joomla will then execute the line:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $container-&amp;gt;get($type);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
where &amp;lt;tt&amp;gt;$type&amp;lt;/tt&amp;gt; contains &#039;Joomla\CMS\Extension\ComponentInterface&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This starts the process of retrieving from the DI container the 3 entries which we put in, and will run our code in services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = new HelloworldComponent($container-&amp;gt;get(ComponentDispatcherFactoryInterface::class));&lt;br /&gt;
    $component-&amp;gt;setMVCFactory($container-&amp;gt;get(MVCFactoryInterface::class));&lt;br /&gt;
    return $component;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We end up with a HelloworldComponent instance, which has:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. a ComponentDispatcherFactory instance passed into the constructor, and which is saved locally by the constructor code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function __construct(ComponentDispatcherFactoryInterface $dispatcherFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;dispatcherFactory = $dispatcherFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This code is in libraries/src/Extension/Component.php, in the class which our HelloworldComponent extends, via the class MVCComponent).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. an MVC Factory instance, stored by the HelloworldComponent &amp;lt;tt&amp;gt;setMVCFactory&amp;lt;/tt&amp;gt; call&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 5 Call boot() on our Component===&lt;br /&gt;
Joomla calls:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
if ($extension instanceof BootableExtensionInterface) {&lt;br /&gt;
        $extension-&amp;gt;boot($container);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will call &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; within our HelloworldComponent, and allows us to perform some initialisation within our component. We&#039;ll return to this later, in the section on [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#HTML_Snippets|HTML snippets]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note again that Joomla checks that our HelloworldComponent class implements BootableExtensionInterface before calling &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt;. It&#039;s not sufficient to just provide the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, we have to explicitly declare that our HelloworldComponent implements the interface.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 6 Get the Dispatcher===&lt;br /&gt;
Returning to our key line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
we have now accomplished the first part &amp;lt;tt&amp;gt;bootComponent($option)&amp;lt;/tt&amp;gt;, and this has returned our HelloworldComponent instance. Now we call &amp;lt;tt&amp;gt;getDispatcher($app)&amp;lt;/tt&amp;gt; on this instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This code is also in libraries/src/Extension/Component.php, in the Component class which our HelloworldComponent extends:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function getDispatcher(CMSApplicationInterface $application): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;dispatcherFactory-&amp;gt;createDispatcher($application);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We call &amp;lt;tt&amp;gt;createDispatcher&amp;lt;/tt&amp;gt; on our ComponentDispatcherFactory class instance which we saved in Step 4. This code is in libraries/src/Dispatcher/ComponentDispatcherFactory.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createDispatcher(CMSApplicationInterface $application, Input $input = null): DispatcherInterface&lt;br /&gt;
    {&lt;br /&gt;
        $name = ucfirst($application-&amp;gt;getName());&lt;br /&gt;
    &lt;br /&gt;
        $className = &#039;\\&#039; . trim($this-&amp;gt;namespace, &#039;\\&#039;) . &#039;\\&#039; . $name . &#039;\\Dispatcher\\Dispatcher&#039;;&lt;br /&gt;
    &lt;br /&gt;
        if (!class_exists($className)) {&lt;br /&gt;
            if ($application-&amp;gt;isClient(&#039;api&#039;)) {&lt;br /&gt;
                $className = ApiDispatcher::class;&lt;br /&gt;
            } else {&lt;br /&gt;
                $className = ComponentDispatcher::class;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    &lt;br /&gt;
        return new $className($application, $input ?: $application-&amp;gt;input, $this-&amp;gt;mvcFactory);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The code checks if we have our own Dispatcher class (our Helloworld tutorial doesn&#039;t, but &amp;lt;tt&amp;gt;com_users&amp;lt;/tt&amp;gt; for example has its own). So it creates a &amp;lt;tt&amp;gt;ComponentDispatcher&amp;lt;/tt&amp;gt; instance, and passes into its constructor the MVC Factory instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Remember that this ComponentDispatcherFactory instance is what was instantiated when it was retrieved from our child DI Container (from being inserted in step 3b), and hence it already knows about our namespace, and has a pointer to our MVCFactory class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Step 7 call dispatch()===&lt;br /&gt;
This is the final aspect to our line of code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$app-&amp;gt;bootComponent($option)-&amp;gt;getDispatcher($app)-&amp;gt;dispatch();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We&#039;re now back to what was described in the Dispatcher section above, except that now we can see that this Dispatcher instance has a pointer to our MVC Factory instance (which knows about our namespace prefix), so when the Dispatcher code wants to create a Controller it can use that MVC Factory instance to instantiate it.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s been a long and tortuous journey to get here, but the significant thing is that all of our key class instances have been obtained via the DI Container. If we want to mock out any of those classes for testing then all we need to do is replace the relevant services/provider file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Javascript and the Web Asset Manager ==&lt;br /&gt;
The web asset manager has been introduced in Joomla 4 and is well documented [[J4.x:Web_Assets|here]]. It provides a much-improved means of managing JS and CSS resources, and a framework for handling their dependencies.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Component Javascript and CSS files should now be stored in the &amp;lt;tt&amp;gt;media&amp;lt;/tt&amp;gt; folder, and the Web Asset Manager used to register them and output them on specific web pages.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The following assets have been registered in the tutorial &amp;lt;tt&amp;gt;joomla.asset.json&amp;lt;/tt&amp;gt;, and you should have a look at that file now.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.validate-greeting===&lt;br /&gt;
This is the code for client validation of the helloworld greeting field using a regex, and it is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that it is dependent upon jQuery and the Joomla &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script, so those both get included as dependencies. &lt;br /&gt;
If we didn&#039;t have specific validation on our form then we would need to include explicitly the &amp;lt;tt&amp;gt;form.validator&amp;lt;/tt&amp;gt; script in order for the basic Joomla field validation to be included, eg in the tmpl file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;document-&amp;gt;getWebAssetManager()-&amp;gt;useScript(&#039;form.validate&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that this requires us to have a &amp;lt;tt&amp;gt;class=&amp;quot;form-validate&amp;quot;&amp;lt;/tt&amp;gt; on the &amp;lt;/tt&amp;gt;&amp;lt;form&amp;gt;&amp;lt;/tt&amp;gt; html element.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.fix-permissions-ajax-call===&lt;br /&gt;
This is the code which copies the value from the greeting field into the title field, so that the Ajax calls setting the permissions work correctly. The js code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.enable-tooltips===&lt;br /&gt;
This is the code which enables bootstrap tooltips to operate, including allowing them to include html code. It&#039;s used to display the image as a tooltip within the admin &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.openstreetmap===&lt;br /&gt;
This is defined as a preset, comprising the helloworld js and css code for the map display, as well as the dependency named &#039;com_helloworld.openlayers&#039; relating to the openlayers CSS and js code. The code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_helloworld.admin-helloworlds-modal===&lt;br /&gt;
This is the js code for selecting an individual helloworld record within a modal, and passing its details to the form in the main window.  Its code is unchanged.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===submitbutton.js===&lt;br /&gt;
In the Joomla 3 code we introduced in [[Special:MyLanguage/J3.2:Developing_an_MVC_Component/Adding_verifications|Adding Verifications]] a js file which controlled when the form was submitted. It differentiated between buttons such as &amp;lt;tt&amp;gt;Save&amp;lt;/tt&amp;gt; (which submitted the form) and &amp;lt;tt&amp;gt;Cancel&amp;lt;/tt&amp;gt; (which didn&#039;t).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 there is a more sophisticated version of &amp;lt;tt&amp;gt;Joomla.submitbutton&amp;lt;/tt&amp;gt; (found in media/system/js/core.js) which uses the CSS classes which the Toolbar functionality sets on the buttons to determine whether the form should be submitted or not. And you can override whether the validation is performed by adding a third parameter to the &amp;lt;tt&amp;gt;submitbutton&amp;lt;/tt&amp;gt; js call. For example, to avoid validation being performed when a button is clicked you can set on the button element:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
onclick=&amp;quot;Joomla.submitbutton(&#039;controller.method&#039;, &#039;&#039;, false)&amp;quot;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
As this is sufficient for what we need in the tutorial, the custom &amp;lt;tt&amp;gt;submitbutton.js&amp;lt;/tt&amp;gt; has been removed.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Interaction with other components ==&lt;br /&gt;
The way that Joomla interacts with components has changed in Joomla 4. In general the Joomla functionality will boot the component using something like:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$extension = $app-&amp;gt;bootComponent($option);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and in our case this will return an instance of the &amp;lt;tt&amp;gt;HelloworldComponent&amp;lt;/tt&amp;gt; class. It will then try to call certain methods on our extension object, as described below.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_categories===&lt;br /&gt;
In the backend the helloworld functionality can display to the administrator &lt;br /&gt;
* the view of the helloworld messages  &lt;br /&gt;
* the view of the helloworld categories&lt;br /&gt;
The categories view is generated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt;, and in Joomla 4 these component categories views display the number of component records there are for each of the possible published status values. To do this the categories component executes the following code (in administrator/components/com_categories/src/Model/CategoriesModel.php):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof CategoryServiceInterface) {&lt;br /&gt;
        $component-&amp;gt;countItems($items, $section);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So our HelloworldComponent must:&lt;br /&gt;
* declare that it implements &amp;lt;tt&amp;gt;CategoryServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide an implementation of &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt;&lt;br /&gt;
We provide &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; by using a trait in libraries/src/Categories/CategoryServiceTrait.php, which (with the assistance of a helper function) does the query on our behalf. We just need to tell it:&lt;br /&gt;
* the name of our table – in the callback &amp;lt;tt&amp;gt;getTableNameForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the database field in which we hold the published status – in &amp;lt;tt&amp;gt;getStateColumnForSection&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_associations===&lt;br /&gt;
Remember that &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; is the component which is run whenever you click on Multilingual Associations in the admin backend.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Under Joomla 3 we provided an associations helper file as described in [[J3.x:Multilingual Associations/Developers|Multilingual Associations/Developers]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the helper file remains basically the same, but &amp;lt;tt&amp;gt;com_associations&amp;lt;/tt&amp;gt; primarily tries to find the helper file via the extension class; here&#039;s the code:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($extensionName);&lt;br /&gt;
    if ($component instanceof AssociationServiceInterface) {&lt;br /&gt;
       return $component-&amp;gt;getAssociationsExtension();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It&#039;s expecting that:&lt;br /&gt;
* the extension (HelloworldComponent in our case) implements &amp;lt;tt&amp;gt;AssociationServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* its &amp;lt;tt&amp;gt;getAssociationsExtension&amp;lt;/tt&amp;gt; method returns the helper class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The easiest thing would be just to code &amp;lt;tt&amp;gt;getAssociationsMethod&amp;lt;/tt&amp;gt; and get it to return &amp;lt;tt&amp;gt;new AssociationsHelper&amp;lt;/tt&amp;gt;. However, we follow the Joomla 4 principle of putting key classes into the Dependency Injection container, and retrieving them later, by having the following code in our services/provider.php:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;set(AssociationExtensionInterface::class, new AssociationsHelper());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The above line puts a key-value pair into our child DI container&lt;br /&gt;
* key = &#039;Joomla\CMS\Association\AssociationExtensionInterface&#039;&lt;br /&gt;
* value is an instance of our &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class. &lt;br /&gt;
We then retrieve it later and use the setter:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setAssociationExtension($container-&amp;gt;get(AssociationExtensionInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so that whenever&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getAssociationExtension()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
is called it returns the &amp;lt;tt&amp;gt;AssociationsHelper&amp;lt;/tt&amp;gt; class instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_fields===&lt;br /&gt;
&amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; is the component which is run when an administrator clicks on the Fields or Field Groups menuitem within the backend, and this functionality was included in the [[J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Adding Custom Fields]] tutorial step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; component stores the custom fields and field groups for all components in the database tables &amp;lt;tt&amp;gt;#__fields&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;#__fields_groups&amp;lt;/tt&amp;gt;, and these tables are partitioned into &amp;quot;sections&amp;quot;, one section per component. For our helloworld component the section is named &amp;quot;helloworld&amp;quot;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within the section we have 2 &amp;quot;contexts&amp;quot; – one for the helloworld messages (called &amp;quot;com_helloworld.helloworld&amp;quot;) and one for the helloworld categories (called &amp;quot;com_helloworld.categories&amp;quot;). This enables us to define custom fields for both our helloworld records and helloworld category records.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; runs it checks both the section and contexts at various times. For example, when an admin selects Helloworld / Fields on the backend then &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; checks the section which was defined in the menuitem in the manifest file (see [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Sidebar|below]]). Here&#039;s the code in administrator/components/com_fields/src/Helpers/FieldsHelper &amp;lt;tt&amp;gt;extract&amp;lt;/tt&amp;gt; function:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        $newSection = $component-&amp;gt;validateSection($parts[1], $item);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And when &amp;lt;tt&amp;gt;com_fields&amp;lt;/tt&amp;gt; wants to display the little dropdown menu of contexts (to allow the administrator to set custom fields on either helloworld items or categories) it calls (in administrator/components/com_fields/src/Fields/FieldcontextsField.php &amp;lt;tt&amp;gt;getOptions()&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component = Factory::getApplication()-&amp;gt;bootComponent($parts[0]);&lt;br /&gt;
    if ($component instanceof FieldsServiceInterface) {&lt;br /&gt;
        return $component-&amp;gt;getContexts();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So it&#039;s clear that our component extension class must :&lt;br /&gt;
* implement &amp;lt;tt&amp;gt;FieldsServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* provide the &amp;lt;tt&amp;gt;validateSection&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getContexts&amp;lt;/tt&amp;gt; methods&lt;br /&gt;
So in upgrading to Joomla 4 we&#039;ve just moved those two methods from the helper file to the extension class.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Router===&lt;br /&gt;
The Joomla router will access our custom router code:&lt;br /&gt;
* whenever it wants to parse an SEF route which it has identified as belonging to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;&lt;br /&gt;
* whenever it wants to build an SEF route from a call to &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; where the option = &amp;quot;com_helloworld&amp;quot;.&lt;br /&gt;
To find our custom router it will:&lt;br /&gt;
* boot the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; extension&lt;br /&gt;
* check that the extension implements &amp;lt;tt&amp;gt;RouterServiceInterface&amp;lt;/tt&amp;gt;&lt;br /&gt;
* call &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; on our extension instance&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In our services/provider.php file we have (careful again - 2 different RouterFactory classes!):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$container-&amp;gt;registerServiceProvider(new RouterFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which from libraries/src/Extension/Service/Provider/RouterFactory.php puts into our child DI container an entry with:&lt;br /&gt;
* key = &amp;quot;Joomla\CMS\Component\Router\RouterFactoryInterface&amp;quot;&lt;br /&gt;
* value is a &amp;lt;tt&amp;gt;\Joomla\CMS\Component\Router\RouterFactory&amp;lt;/tt&amp;gt; instance, constructed with our namespace&lt;br /&gt;
We then retrieve this in the line in our services/provider.php file:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setRouterFactory($container-&amp;gt;get(RouterFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
And then within our extension class we have&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use RouterServiceTrait;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which includes&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function setRouterFactory(RouterFactoryInterface $routerFactory)&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;routerFactory = $routerFactory;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which stores the &amp;lt;tt&amp;gt;routerFactory&amp;lt;/tt&amp;gt; locally and&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return $this-&amp;gt;routerFactory-&amp;gt;createRouter($application, $menu);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which provides our extension&#039;s &amp;lt;tt&amp;gt;createRouter&amp;lt;/tt&amp;gt; call that the Joomla Router expects.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;routerFactory::createRouter&amp;lt;/tt&amp;gt; method is in libraries/src/Component/Router/RouterFactory.php. It looks for a class in our site namespace &amp;lt;/tt&amp;gt;Robbie\Component\Helloworld\Site\Service\Router&amp;lt;/tt&amp;gt; which is in our site/src/Service/Router.php.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
At this stage we have a choice, we can either:&lt;br /&gt;
* provide a traditional custom router, with the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions, or&lt;br /&gt;
* use the more modern &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; mechanism. &lt;br /&gt;
By default in the upgraded tutorial code the Router View option has been coded in the Router.php file.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====RouterView====&lt;br /&gt;
In the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; case the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; functions are in the &amp;lt;tt&amp;gt;RouterView&amp;lt;/tt&amp;gt; class which we extend, and we provide &lt;br /&gt;
* a constructor with router view configuration&lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldId&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategoryId&amp;lt;/tt&amp;gt; which are used to obtain from the SEF segment the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts of the internal URL &lt;br /&gt;
* methods &amp;lt;tt&amp;gt;getHelloworldSegment&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getCategorySegment&amp;lt;/tt&amp;gt; which are used to generate segments for the SEF URLs based on the &amp;lt;tt&amp;gt;id=&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;catid=&amp;lt;/tt&amp;gt; parts within the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
Unfortunately there doesn&#039;t seem to be a good guide to configuring the RouterView class. There is some documentation available [https://www.dionysopoulos.me/book/com-router-routerview.html here].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the helloworld tutorial we have 3 views&lt;br /&gt;
* a view which displays a single helloworld record&lt;br /&gt;
* a view which displays a single helloworld category, and the helloworld records associated with it&lt;br /&gt;
* a view which displays the frontend form&lt;br /&gt;
So we need 3 Router Views associated with these.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;form&#039; view doesn&#039;t have an associated id or catid so it&#039;s just a fixed URL, and the router just has to convert between the alias of the form menuitem and the Itemid / view parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;category&#039; view has an associated id (of the category record), and an SEF URL will use the category path down the Categories Nested Set table structure, hence &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &#039;helloworld&#039; view has an associated id (of the helloworld record), and in an SEF URL in the category view the helloworld record alias is added to the category path (hence &amp;lt;tt&amp;gt;setParent()&amp;lt;/tt&amp;gt;). But although the helloworld records use a Nested Table structure in the database, the URLs just include the alias of the single record, and so &amp;lt;tt&amp;gt;setNestable()&amp;lt;/tt&amp;gt; is not used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There doesn&#039;t seem to be a way to configure an additional SEF URL scheme which just displays a helloworld segment, without a category segment.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
====Traditional Router====&lt;br /&gt;
To use the traditional router in the tutorial code you should uncomment the function in the extension class:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public function createRouter(CMSApplicationInterface $application, AbstractMenu $menu): RouterInterface&lt;br /&gt;
    {&lt;br /&gt;
        return new TraditionalRouter($application, $menu, $this-&amp;gt;categoryFactory, $this-&amp;gt;getDatabase());&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will cause the code in site/src/Service/TraditionalRouter.php to be used. However, changes in the Joomla 4 router mean that the interaction between it and the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; methods have changed. This requires significant changes to the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; methods, but only a minor change to &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
1. Previously Joomla injected into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; of the active menuitem (ie the id of the menuitem the user is currently on). This meant that we had to change the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; for links generated by the Language Switcher module (which generates the flags for switching between languages), and these links being associated with a different language would obviously use a different &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 you get an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters only if you specified an &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; in the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; call. For others you have to work out which menuitem to use yourself, by using the Joomla menu/menuitems API to find details of the configured menuitems, and work out which to use based on the other &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
You do this in the &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, and then the &amp;lt;tt&amp;gt;Itemid&amp;lt;/tt&amp;gt; you set will be passed in the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters to the &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
2. In some instances the &amp;lt;tt&amp;gt;Route::_()&amp;lt;/tt&amp;gt; URL you&#039;re generating matches exactly one of the configured menuitems on the site. In this case the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will match those in the menuitem &amp;lt;tt&amp;gt;&amp;quot;query&amp;quot;&amp;lt;/tt&amp;gt; array, and you have to remove explicitly remove the &#039;view&#039;, &#039;id&#039; and &#039;catid&#039; parameters so that they don&#039;t appear as URL query parameters after the normal SEF URL of the menuitem.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
3. The custom router will be used to build the URLs for the helloworld menuitems shown in menus on the page. For these the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters will have the view / id / catid associated with those menuitems. Note that even if you remove these in your &amp;lt;tt&amp;gt;preprocess&amp;lt;/tt&amp;gt; method, Joomla will inject them again into the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; array when it&#039;s passed to your &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; method, so you&#039;ll have to remove them again there!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
4. In the &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; method you now have to unset the &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt;, or else Joomla will return an HTTP 404 (page not found). Otherwise &amp;lt;tt&amp;gt;parse&amp;lt;/tt&amp;gt; works as before.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
5. I&#039;ve implemented &amp;lt;tt&amp;gt;build&amp;lt;/tt&amp;gt; only for when Multilanguage is enabled on the site. If it&#039;s not enabled an empty &amp;lt;tt&amp;gt;$segments&amp;lt;/tt&amp;gt; array is just returned, without doing unset on any of the &amp;lt;tt&amp;gt;$query&amp;lt;/tt&amp;gt; parameters, so these will appear as URL parameters after the SEF URL. Also it&#039;s not coded properly to deal with items which have language set to &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;. These include helloworld records, categories or menuitems (eg the helloworld form).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note also that the &amp;lt;tt&amp;gt;categoryFactory&amp;lt;/tt&amp;gt; is also now passed to the router. This is so that it can be used instead of &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; to get access to the Categories API calls.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===com_tags===&lt;br /&gt;
Whenever we setup a Tags Menu Item Type which displays items having a given tag or tags, then &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; displays those items as links, and uses route helper functions to generate the URL parameters.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The route helpers &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; expects to find loaded into the data of the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table, in the router field, and these have been set to:&lt;br /&gt;
* For links to helloworld items: &#039;HelloworldHelperRoute::getHelloworldRoute&#039;&lt;br /&gt;
* For links to helloworld categories: &#039;HelloworldHelperRoute::getCategoryRoute&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; doesn&#039;t boot the helloworld extension to get access to these, but rather seeks to find them in site/helpers/route.php, so that&#039;s where they continue to be.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(We also had a &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; which was used by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; in administrator/components/com_categories/src/Helper/CategoryAssociationHelper. When a category was displayed on the frontend then the Language Switcher module (now Language Filter) used this function to generate the links to the Associated Categories. Our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; previously was necessary to insert the &amp;lt;tt&amp;gt;lang=&amp;lt;language tag&amp;gt;&amp;lt;/tt&amp;gt; parameter into the link URL, but since [https://github.com/joomla/joomla-cms/pull/39358 this change] the calling function inserts the &amp;lt;tt&amp;gt;lang&amp;lt;/tt&amp;gt; parameter itself, so our &amp;lt;tt&amp;gt;getCategoryRoute&amp;lt;/tt&amp;gt; function for this purposes is superfluous.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Deprecated APIs ==&lt;br /&gt;
With Joomla 4 there are a number of methods which are deprecated, with a view to removing them in Joomla 5.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Factory Methods===&lt;br /&gt;
Many of the &amp;lt;tt&amp;gt;Factory&amp;lt;/tt&amp;gt; methods for getting singleton classes have been deprecated in favour of getting these classes via the DI container, and it appears that  only class instances which should be obtained via Factory methods are:&lt;br /&gt;
* the Application – &amp;lt;tt&amp;gt;Factory::getApplication()&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the DI container – &amp;lt;tt&amp;gt;Factory::getContainer()&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here is a list of what has been changed in the tutorial code. Note that with some calls there are variants available, through the aliases defined in the DI container.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDbo&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\Database\DatabaseInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $db = Factory::getContainer()-&amp;gt;get(DatabaseInterface::class);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, in many classes the database instance is more easily (and efficiently) returned via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$db = $this-&amp;gt;getDatabase();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is available in Model classes, custom field definitions, etc.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getUser();&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get the current user use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = Factory::getApplication()-&amp;gt;getIdentity()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To get a different user (whose id you know):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\User\UserFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    $user = Factory::getContainer()-&amp;gt;get(UserFactoryInterface::class)-&amp;gt;loadUserById($userid);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Within models which extend Joomla\CMS\MVC\Model\BaseDatabaseModel and views which extend Joomla\CMS\MVC\View\HtmlView you can also use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$user = $this-&amp;gt;getCurrentUser()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getDocument()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication()-&amp;gt;getDocument()&amp;lt;/tt&amp;gt;, or within a View you can use &amp;lt;tt&amp;gt;$this-&amp;gt;document&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getConfig()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Two options have been used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getConfig()&amp;lt;/tt&amp;gt; – returns a Registry object containing all the configuration values&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;get(&#039;access&#039;)&amp;lt;/tt&amp;gt; – returns the value of the &#039;access&#039; configuration parameter&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Factory::getLanguage()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by &amp;lt;tt&amp;gt;Factory::getApplication-&amp;gt;getLanguage()&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JFactory::getCache(&#039;com_example&#039;, &amp;lt;type&amp;gt;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Replaced by&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;&lt;br /&gt;
    ...&lt;br /&gt;
    Factory::getContainer()-&amp;gt;get(CacheControllerFactoryInterface::class)-&amp;gt;createCacheController(&amp;lt;type&amp;gt;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated getInstance Methods===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general &amp;lt;tt&amp;gt;getInstance()&amp;lt;/tt&amp;gt; calls have been deprecated in favour of obtaining the instance, either via a factory class or via the DI container. For example, within a controller you can use &amp;lt;tt&amp;gt;getModel()&amp;lt;/tt&amp;gt; repeatedly to get different models (passing the relevant model names), which results in the MVCFactory class creating the Model classes.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there are currently some problems with replacing some getInstance calls. I expect that the Joomla team will resolve these issues over the course of the Joomla 4 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Categories::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This is deprecated with a notice: &amp;quot;Use the ComponentInterface to get the categories&amp;quot;. This means that we should get the category factory instance via the DI container. This is done in our services/provider.php by the lines:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\Extension\Service\Provider\CategoryFactory;&lt;br /&gt;
    ...&lt;br /&gt;
    $container-&amp;gt;registerServiceProvider(new CategoryFactory(&#039;\\Robbie\\Component\\Helloworld&#039;));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to put into our child DI container the closure which will create a Joomla\CMS\Categories\CategoryFactory instance, constructed with our namespace.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when our HelloworldComponent (Extension) instance is created:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We can then use:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$component-&amp;gt;getCategoryFactory()-&amp;gt;createCategory();&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
to create our Categories object, and in this way get access to the Categories APIs.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(This createCategory method creates the instance by looking for the \\Site\\Service\\Category class within our namespace. The constructor in our class sets our extension (&#039;com_helloworld&#039;) and table (&#039;#__helloworld&#039;) and calls the parent Categories constructor with these options).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this means that the section of our code where we want to use the Categories APIs must have a pointer to a CategoryFactory instance. In the tutorial code for Joomla 3 there are 2 places where &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; is used:&lt;br /&gt;
* in the custom router code, to handle building and parsing of the category parts of the SEF URL&lt;br /&gt;
* in the site category model, where the Categories APIs are used to obtain details of categories to display on the page.&lt;br /&gt;
For the custom router code, the CategoryFactory instance is passed as a parameter to the TraditionalRouter constructor so that it can be used there.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, the site category model is instantiated by the MVCFactory instance, and it doesn&#039;t make available a CategoryFactory instance. So in this category model the calls to &amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; have been left, and you can still find a number of calls to &amp;lt;tt&amp;gt;Categories::getInstance&amp;lt;/tt&amp;gt; within Joomla core components.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;Categories::getInstance()&amp;lt;/tt&amp;gt; itself solves the problem of access to a CategoryFactory instance by rebooting our component again to get a pointer to our Extension instance, and thus to the category factory instance. However, this involves a lot of work, so &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; caches locally the Categories instances and just returns one of them if it can.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Pushing the CategoryFactory to the model&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, there is a way to get access to the CategoryFactory instance, by defining your own MVCFactory class, and pushing the instance down through it to the model. Here&#039;s how you can go about it:&lt;br /&gt;
* Define your own SuperMVCFactory class, which extends the Joomla Joomla\CMS\MVC\Factory\MVCFactory class, but which has a means of storing a  CategoryFactory instance. Use the CategoryServiceTrait in libraries/src/Categories/CategoryServiceTrait.php&lt;br /&gt;
* Create your own version of the file libraries/src/Extension/Service/Provider/MVCFactory.php, which is the &#039;provider.php&#039; like file for MVCFactory, but change it so that:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new \Joomla\CMS\MVC\Factory\MVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory = new &amp;lt;namespace&amp;gt;\SuperMVCFactory($this-&amp;gt;namespace);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
and include&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$factory-&amp;gt;setCategoryFactory($container-&amp;gt;get(CategoryFactoryInterface::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When Joomla creates a model such as CategoryModel it passes in its constructor the MVCFactory instance (so that the model can call createTable on it), so you can access it via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This will return your SuperMVCFactory instance. So in this way within the model you can access the CategoryFactory, and use it to create the Categories instance via&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getMVCFactory()-&amp;gt;getCategory() (from the CategoryServiceTrait)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
If you can get this working you can congratulate yourself on a good understanding of Joomla namespacing and dependency injection! A similar approach to address a similar problem is described [https://www.dionysopoulos.me/book/com-router-push-dependencies.html here]. If you get stuck you can always view the solution by viewing the github tutorial code selecting the branch [https://github.com/robbiejackson/Joomla-4-MVC-Tutorial/tree/push-category-factory-to-mvc push-category-factory-to-mvc].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Table::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
There are a couple of calls to &amp;lt;tt&amp;gt;Table::getInstance()&amp;lt;/tt&amp;gt; within admin/src/Helper/AssociationsHelper.php in &amp;lt;tt&amp;gt;getItem()&amp;lt;/tt&amp;gt;:&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Helloworld&#039;, &#039;Robbie\\Component\\Helloworld\\Administrator\\Table\\&#039;)&amp;lt;/tt&amp;gt; to get an instance of our HelloworldTable class.&lt;br /&gt;
* &amp;lt;tt&amp;gt;Table::getInstance(&#039;Category&#039;)&amp;lt;/tt&amp;gt; to get an instance of the Category table in libraries/src/Table/Category.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We could actually arrange for the AssociationsHelper class to get injected with the MVCFactory instance, so that the HelloworldTable class could be instantiated by it. However, we couldn&#039;t use the helloworld MVCFactory instance to create the Category table instance, as it&#039;s not in the helloworld namespace, and our MVCFactory instance creates table instances within our namespace only.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Toolbar::getInstance()&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The tutorial code uses &amp;lt;tt&amp;gt;Toolbar::getInstance()&amp;lt;/tt&amp;gt; to get a Toolbar instance onto which it can attach the batch button in the helloworlds form. The Toolbar API documentation seems to suggest that we should replace&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Toolbar::getInstance(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
with&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$bar = Factory::getContainer()-&amp;gt;get(ToolbarFactoryInterface::class)-&amp;gt;createToolbar(&#039;toolbar&#039;);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, this currently won&#039;t work. The problem is that all the other Joomla code uses &amp;lt;tt&amp;gt;getInstance(&#039;toolbar&#039;)&amp;lt;/tt&amp;gt; to access the Toolbar class, including the code in administrator/modules/mod_toolbar/mod_toolbar.php which renders the toolbar. The &amp;lt;tt&amp;gt;getInstance&amp;lt;/tt&amp;gt; method keeps track of the Toolbar instances in a local static variable &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt;, and returns the same Toolbar instance on repeated invocations.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So if you use the second approach above you will get a Toolbar instance, but it won&#039;t be the same Toolbar instance as is stored in the &amp;lt;tt&amp;gt;$instances&amp;lt;/tt&amp;gt; variable. It won&#039;t then be picked up by the Toolbar module, and so won&#039;t be rendered on the form.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Error Handling===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Instead of&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   JError::raiseError(500, implode(&#039;&amp;lt;br /&amp;gt;&#039;, $errors));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
you should throw an exception, using or extending one of the standard [https://www.php.net/manual/en/spl.exceptions.php PHP exceptions], eg&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   throw new \Exception(implode(&amp;quot;\n&amp;quot;, $errors), 500); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===jimport===&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
jimport is no longer necessary in order to get access to Path or File classes. All of the Joomla classes are found by the autoloader.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Deprecated Methods related to Javascript===&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.framework&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In general, the use of JHtml::_(&#039;behavior.xxx&#039;) is now obsolete, and calls using this have been removed in the tutorial code. The &#039;behavior.framework&#039; call referred to including jQuery. Where jQuery is necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.formvalidator&#039;);&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This has been replaced by the &amp;lt;tt&amp;gt;form.validate&amp;lt;/tt&amp;gt; javascript asset, and where necessary it has now been included as a dependency in an entry within the helloworld joomla.asset.json file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
It can also be included directly using the web asset manager:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$wa-&amp;gt;useScript(&#039;form.validate&#039;)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;behavior.tooltip&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This no longer exists, and tooltips don&#039;t seem to be enabled by default in Joomla 4. This is replaced by the code in media/js/enable-tooltips.js.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;JHtml::_(&#039;formbehavior.chosen&#039;)&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The chosen js library seems to be no longer used, and using it will cause formatting issues if you include it in your tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;sortable&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The sortable js library provided the ability in the helloworlds view to drag rows up and down to change the ordering of the records. This has been replaced in Joomla 4 by the draggable library. To enable it you have to set:&lt;br /&gt;
* &amp;lt;tt&amp;gt;HTMLHelper::_(&#039;draggablelist.draggable&#039;);&amp;lt;/tt&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; element define the table in which dragging occurs and the URL of the Ajax call to set the ordering: &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tbody&amp;lt;?php if ($saveOrder) : ?&amp;gt; class=&amp;quot;js-draggable&amp;quot; data-url=&amp;quot;&amp;lt;?php echo $saveOrderingUrl; ?&amp;gt;&amp;quot; data-direction=&amp;quot;&amp;lt;?php echo strtolower($listDirn); ?&amp;gt;&amp;quot; data-nested=&amp;quot;true&amp;quot;&lt;br /&gt;
      &amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* on your &amp;lt;tt&amp;gt;tr&amp;lt;/tt&amp;gt; element within your &amp;lt;tt&amp;gt;&amp;lt;tbody&amp;gt;&amp;lt;/tt&amp;gt; define the group of records in which dragging occurs (by category below): &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr class=&amp;quot;row&amp;lt;?php echo $i % 2; ?&amp;gt;&amp;quot; data-draggable-group=&amp;quot;&amp;lt;?php echo $row-&amp;gt;catid; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==HTML Snippets==&lt;br /&gt;
There are two places in the tutorial where reusable snippets of HTML have beeen defined:&lt;br /&gt;
* For displaying the item associations in the helloworlds view:&lt;br /&gt;
* For displaying the position latitude and longitude fields within the batch options in the helloworlds view&lt;br /&gt;
These used different approaches:&lt;br /&gt;
* the item associations display was coded in an html helper file in admin/helpers/html/helloworlds.php and accessed via&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JHtml::_(&#039;helloworlds.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
in the helloworlds tmpl file. (Although it did use a common joomla layout file underneath).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* the position field was coded as a layout in layouts/position.php, and rendered using&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo JLayoutHelper::render(&#039;position&#039;, array());&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
When should you use one approach rather than the other? A significant difference is that layouts are designed so that an administrator can override them, via the Templates / Details and File functionality. So, for example, an administrator could change the position to show the longitude before the latitude. So it&#039;s more appropriate for layouts to focus on the html elements rather than functional logic, and particularly if you would want to allow an administrator to override the layout.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The layouts functionality in Joomla 4 hasn&#039;t changed significantly. One correction which has been made in the updated tutorial code has been to include the position.php file in a subfolder of layouts, ie in admin/layouts/helloworld/position.php rather than admin/layouts/position.php. It appears that in the Templates / Details and Files / Create Overrides tab the &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt; layout appears only if it&#039;s in a subfolder of /layouts.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The &amp;lt;tt&amp;gt;JHtml::_()&amp;lt;/tt&amp;gt; approach has changed in Joomla 4. Rather than Joomla having to look for a helper file when it encounters something it doesn&#039;t recognise, it&#039;s expected that you should register such classes beforehand, and you do this by obtaining an instance of the Joomla\CMS\HTML\Registry class (it&#039;s a singleton class) and then calling &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; on it, passing&lt;br /&gt;
* the key you want to use&lt;br /&gt;
* an instance of your class&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The Joomla pattern is to put the code in a file admin/src/Service/HTML/AdministratorService.php, and we have to ensure that our key won&#039;t be used elsewhere within Joomla, so in the tutorial we&#039;ve used:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Robbie\Component\Helloworld\Administrator\Service\HTML\AdministratorService;&lt;br /&gt;
    ...&lt;br /&gt;
    register(&#039;helloworldadministrator&#039;, new AdministratorService)&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Then when we call:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
echo HTMLHelper::_(&#039;helloworldadministrator.association&#039;, $row-&amp;gt;id);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
it will result in Joomla calling the &amp;lt;tt&amp;gt;association&amp;lt;/tt&amp;gt; method in our class, passing the &amp;lt;tt&amp;gt;$row-&amp;gt;id&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
We should get the Joomla\CMS\HTML\Registry class from the Dependency Injection container. Joomla components generally do this via their services/provider.php file, and then call &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; within the extension&#039;s &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function, described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#Step_5_Call_boot.28.29_on_our_Component|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The extension uses HTMLRegistryAwareTrait which contains &amp;lt;tt&amp;gt;setRegistry&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;getRegistry methods&amp;lt;/tt&amp;gt;. In services/provider.php there is:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
use Joomla\CMS\HTML\Registry;&lt;br /&gt;
    ...&lt;br /&gt;
    $component-&amp;gt;setRegistry($container-&amp;gt;get(Registry::class));&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets &#039;Joomla\CMS\HTML\Registry&#039; out of the DI container and stores it within the&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
private $registry;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
variable of the HTMLRegistryAwareTrait included in the extension.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; function it calls&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;getRegistry()-&amp;gt;register(&#039;helloworldadministrator&#039;, new AdministratorService);&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
which gets the registry and calls &amp;lt;tt&amp;gt;register&amp;lt;/tt&amp;gt; as required.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Note that &amp;lt;tt&amp;gt;boot&amp;lt;/tt&amp;gt; is called whenever Joomla dispatches &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;, both for the site and administrator, so it would make sense to check the Application &amp;lt;tt&amp;gt;isClient&amp;lt;/tt&amp;gt; before deciding whether to register the HTML Helper service or not. This hasn&#039;t been included in the tutorial code though.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==User Interface Changes==&lt;br /&gt;
Joomla 4 introduced new templates, atum on administrator and cassiopeia on site, and in particular the administrator is built upon some UI rearrangements which affect the tutorial code.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Sidebar===&lt;br /&gt;
In Joomla 3 each component incorporated a sidebar which we coded in the &amp;lt;tt&amp;gt;addSubmenu&amp;lt;/tt&amp;gt; function in admin/helpers/helloworld.php.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 the administrator menu is in a vertical panel on the left hand side, and the Hello World submenu is built from entries in the helloworld.xml manifest file.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;administration&amp;gt;&lt;br /&gt;
        &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;submenu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_MENU&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_categories&amp;amp;amp;extension=com_helloworld&amp;quot;&amp;gt;COM_HELLOWORLD_CATEGORIES&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=fields&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS&amp;lt;/menu&amp;gt;&lt;br /&gt;
            &amp;lt;menu link=&amp;quot;option=com_fields&amp;amp;amp;view=groups&amp;amp;amp;context=com_helloworld.helloworld&amp;quot;&amp;gt;MOD_MENU_FIELDS_GROUP&amp;lt;/menu&amp;gt;&lt;br /&gt;
        &amp;lt;/submenu&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===CSS Classes===&lt;br /&gt;
In several places the CSS classes defined in the html elements have been changed in Joomla 4. For example, for general layout the classes now align with the [https://getbootstrap.com/docs/3.4/css/ Bootstrap CSS Classes], and classes such as &amp;lt;tt&amp;gt;row-fluid&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;span3&amp;lt;/tt&amp;gt; which were prominent in Joomla 3 have disappeared. If you&#039;re upgrading a Joomla 3 component then it&#039;s probably best (on the back-end at least) to find a similar Joomla component and use the overall html structure and css classes within its tmpl files.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In the tutorial code those classes which are specifically used by Bootstrap have been changed from eg &#039;data-target&#039; to &#039;data-bs-target&#039;, and it has been necessary to change these to enable the functionality to work.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
However, not all of CSS class changes affecting solely the presentation have been reflected in the updated tutorial code. For example, in the &amp;lt;tt&amp;gt;helloworlds&amp;lt;/tt&amp;gt; view, showing the list of helloworld messages, the display of the associations is different from that of other Joomla components.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Fonts===&lt;br /&gt;
In Joomla 3 [[J3.x:Joomla_Standard_Icomoon_Fonts|Icomoon Fonts]] were used.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 Font Awesome&#039;s free icons are used, and you can see what is available on their [https://fontawesome.com/v5/cheatsheet cheatsheet]. The icons are implemented using CSS pseudo-elements, as described [https://fontawesome.com/v5/docs/web/advanced/css-pseudo-elements here].  Basically they convert a CSS class into html content, namely a unicode value in the private use range. A couple of these have been implemented in the frontend form, in the Save and Cancel buttons, for example:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;/span  &amp;lt;?php echo Text::_(&#039;JCANCEL&#039;) ?&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
(with angle brackets removed from the &amp;lt;tt&amp;gt;span&amp;lt;/tt&amp;gt; tags to stop the icon just being displayed by the browser).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This class is defined in media/system/css/joomla-fontawesome.css (where you can find the list of icon classes supported):&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
.icon-cancel:before {&lt;br /&gt;
      content: &amp;quot;\f00d&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
so this includes in front of the text the unicode character &amp;lt;tt&amp;gt;f00d&amp;lt;/tt&amp;gt;, which you can see on the cheatsheet as &amp;quot;times&amp;quot;, and displayed as &amp;lt;span class=&amp;quot;icon-cancel&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;. You can also use &amp;lt;tt&amp;gt;fa-&amp;lt;/tt&amp;gt; plus the icon name on the font awesome cheatsheet page. If you use Icomoon icon names in your code which you run under Joomla 4, then the icon displayed will be a Font Awesome icon (if there&#039;s one with the same name) or it will use a mapping which the Joomla team have defined to display a Font Awesome icon which resembles the Icomoon one.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Buttons and Links===&lt;br /&gt;
An accessibility principle is that &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; html elements should be used for links to other web pages, and &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements should be used for actions, eg on a form. To align with this, the &amp;lt;tt&amp;gt;&amp;lt;a&amp;gt;&amp;lt;/tt&amp;gt; elements in the helloworld modal field (defined in admin/src/Field/Modal/Helloworld.php) have been changed to &amp;lt;tt&amp;gt;&amp;lt;button&amp;gt;&amp;lt;/tt&amp;gt; elements. These are the Select and Clear buttons displayed when choosing a Helloworld record for a menuitem pointing to a Helloworld message. (The buttons also include fontawesome icons, by the way).&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
This change was actually made in Joomla in one of the Joomla 3 releases.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Categories View===&lt;br /&gt;
In the Categories view of standard Joomla components there now appears columns which show for each category the number of items, split by published status. This is populated by &amp;lt;tt&amp;gt;com_categories&amp;lt;/tt&amp;gt; calling each extension&#039;s &amp;lt;tt&amp;gt;countItems&amp;lt;/tt&amp;gt; function, as described [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_categories|above]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Miscellaneous Changes==&lt;br /&gt;
===Version History===&lt;br /&gt;
In Joomla 3 the tutorial code used the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; functionality to copy relevant changes from the Helloworld and Categories tables into the UCM tables.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
In Joomla 4 it uses a plugin mechanism to subscribe to Table events &#039;onTableAfterStore&#039; and &#039;onTableBeforeDelete&#039;. The plugin can be found in plugins/behaviour/versionable, and it is activated by Joomla as part of its application initialisation.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
The copying of fields from the table works roughly the same way as before, except that the name of the table where the versions are stored is now &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt;, so the entries which have to be inserted into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table are fairly similar. Because the folders in which forms are stored has changed in Joomla 4, the &#039;formFile&#039; parameter is different (remember that this is where Joomla gets the field labels in order to display the Preview within the Versions modal window, otherwise just the names of the database columns will be output).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Here&#039;s a summary of what needs to be done to enable versioning under Joomla 4. The Versioning Traits and Interface definitions are found in libraries/src/Versioning:&lt;br /&gt;
* Enter data into content_types database table&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Storing the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The Table class must implement VersionableTableInterface and provide &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt;, which returns &#039;com_helloworld.helloworld&#039;. This type alias + the helloworld record id is used as the key to identify versions in the &amp;lt;tt&amp;gt;#__history&amp;lt;/tt&amp;gt; table. &lt;br /&gt;
* Define &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;history_limit&amp;lt;/tt&amp;gt; options in config.php, and ensure these are both set.&lt;br /&gt;
* Add a &amp;lt;tt&amp;gt;version_note&amp;lt;/tt&amp;gt; field into the output of the edit view&#039;s tmpl file (admin/tmpl/helloworld/edit.php).&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Viewing and Restoring the history:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit Controller (admin/src/Controller/HelloworldController.php) should &amp;lt;tt&amp;gt;use VersionableControllerTrait&amp;lt;/tt&amp;gt;. &lt;br /&gt;
* The edit Model (admin/src/Model/HelloworldModel.php) should &amp;lt;tt&amp;gt;use VersionableModelTrait&amp;lt;/tt&amp;gt; and include a variable&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
public $typeAlias = &#039;com_helloworld.helloworld&#039;;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
* The edit View (admin/src/View/Helloworld/HtmlView.php) – should display the Versions toolbar button if global config has &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; on.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Joomla 4 allows us to have different history version limits for helloworld items and categories, and this has been used in the configuration definition in admin/config.xml.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Setting Configuration Parameters in Install Script===&lt;br /&gt;
As you may remember, global configuration parameters relating to the Hello World component are defined in admin/config.xml and stored in the &amp;lt;tt&amp;gt;#__extensions&amp;lt;/tt&amp;gt; table, in a JSON string in the params field of the record relating to &amp;lt;tt&amp;gt;com_helloworld&amp;lt;/tt&amp;gt;. This means that when the component is first installed the params are not set.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
So, for example, even if the &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; is defined in config.xml to default to true, the versions won&#039;t be saved until an administrator actively saves the configuration parameters, because the Joomla versioning code assumes &amp;lt;tt&amp;gt;save_history&amp;lt;/tt&amp;gt; to be false if it&#039;s not explicitly set.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
For this reason it makes sense to set any default configuration parameters in the install script.php, in the &amp;lt;tt&amp;gt;postflight&amp;lt;/tt&amp;gt; method, and that has been done in this step.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===Tags===&lt;br /&gt;
Like version history, tags functionality has been changed to use a plugin – in plugins/behaviour/taggable – rather than the &amp;lt;tt&amp;gt;JTableObserver&amp;lt;/tt&amp;gt; approach.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
To enable tags the component table must implement TaggableTableInterface (in libraries/src/Tag), and provide the &amp;lt;tt&amp;gt;getTypeAlias()&amp;lt;/tt&amp;gt; which is common to the Versioning functionality.&lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Whenever &amp;lt;tt&amp;gt;com_tags&amp;lt;/tt&amp;gt; outputs helloworld messages or categories relating to a tag it displays them as links, and looks in the site/helpers/route.php file to find the route functions (as described above in [[J3.x:Developing_an_MVC_Component/Upgrading_to_Joomla4#com_tags|com_tags]]). The class and method in this file must match the &#039;router&#039; field within the data entered into the &amp;lt;tt&amp;gt;#__content_types&amp;lt;/tt&amp;gt; table.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
===media files===&lt;br /&gt;
Under Joomla 4 all of the media files are stored in the /media folder; these include javascript and css files (scss files too), as well as images such as the little flag symbols shown in the language switcher. Extensions being developed should store all of the js and css files in their /media folder, and then when the extension is installed these files are put under the extension&#039;s folder under the /media folder of the Joomla instance.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
==Patches==&lt;br /&gt;
Some bugs in Joomla were discovered during the course of updating the tutorial code to work under Joomla 4. If you find something doesn&#039;t work then make sure you&#039;re on at least Joomla 4.2.6 and check if you need one of the following patches:&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
CategoryAssociationHelper.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39358/files&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
MediaField.php&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/issues/39203&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
Category restore&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
https://github.com/joomla/joomla-cms/pull/39474&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
== Contributors ==&lt;br /&gt;
*[[User:Robbiej|Robbie Jackson]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div lang=&amp;quot;en&amp;quot; dir=&amp;quot;ltr&amp;quot; class=&amp;quot;mw-content-ltr&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;large-6 columns&amp;quot;&amp;gt;{{Basic button|S:MyLanguage/J3.x:Developing_an_MVC_Component/Adding_Custom_Fields|Prev: Adding Custom Fields|class=expand success}}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ing Pulizzi</name></author>
	</entry>
</feed>