<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: NumberNine CMS</title>
    <description>The latest articles on DEV Community by NumberNine CMS (@numberninecms).</description>
    <link>https://dev.to/numberninecms</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4530%2F2604e237-cf9a-4a2b-aae3-44bd2117b1a4.png</url>
      <title>DEV Community: NumberNine CMS</title>
      <link>https://dev.to/numberninecms</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/numberninecms"/>
    <language>en</language>
    <item>
      <title>Split your Symfony views into multiple controllers with NumberNine CMS</title>
      <dc:creator>William Arin</dc:creator>
      <pubDate>Fri, 13 Aug 2021 16:43:42 +0000</pubDate>
      <link>https://dev.to/numberninecms/split-your-symfony-views-into-multiple-controllers-with-numbernine-cms-2nj0</link>
      <guid>https://dev.to/numberninecms/split-your-symfony-views-into-multiple-controllers-with-numbernine-cms-2nj0</guid>
      <description>&lt;p&gt;When building a simple page with Symfony, we usually end up having a controller and a view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8y4yujvl2cfw9jifqs8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8y4yujvl2cfw9jifqs8.png" alt="Simple controller" width="274" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oftentimes, things get complicated and one controller is not a viable solution anymore, therefore we need to split the view like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss1gg87kgzhtr5n3ss1m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fss1gg87kgzhtr5n3ss1m.png" alt="Multiple controllers" width="600" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Symfony offers several ways to split your views into multiple controllers. NumberNine CMS offers two more. We'll see which cons and pros each method provides.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using Twig partials with &lt;code&gt;include&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="s1"&gt;'my_partial.html.twig'&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'hello'&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;using Twig partials with &lt;code&gt;embed&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;embed&lt;/span&gt; &lt;span class="s1"&gt;'my_partial.html.twig'&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;message&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;hello&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endembed&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;using &lt;a href="https://symfony.com/doc/current/templates.html#embedding-controllers" rel="noopener noreferrer"&gt;embedded controllers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MyController'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'hello'&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;using &lt;a href="https://github.com/symfony/ux-twig-component" rel="noopener noreferrer"&gt;Twig components&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my_component'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'hello'&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;using NumberNine components
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;N9_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MyComponent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'hello'&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;using NumberNine shortcodes
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;N9_shortcode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[my_shortcode message="hello"]'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Pros and cons of each technique
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Twig includes and embeds&lt;/strong&gt; are great and flexible but their data come from above, which makes the root controller bloated. Of course there are workarounds such as Twig extensions or global variables to access a service, but a view shouldn't retrieve data that the controller didn't send to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedded controllers&lt;/strong&gt; are a good solution if they're used sporadically, as they make a new Request and will negatively impact performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Twig Components&lt;/strong&gt; is a better approach than embedded controllers, although they have some limitations. Components are non shared services, which means a new instance is created at every call of &lt;code&gt;{{ component('my_component') }}&lt;/code&gt;, erasing previously stored data. This means that if your component registers an event listener, it won't work as the instance is created on the fly.&lt;/p&gt;
&lt;h2&gt;
  
  
  NumberNine components
&lt;/h2&gt;

&lt;p&gt;NumberNine Components solve the problem of Twig Component's separate instances by creating a new set of template parameters everytime the component is called, but the instance itself of the component stays the same.&lt;/p&gt;

&lt;p&gt;A NumberNine Component is a shared service, hence event listeners registered will catch events as they should. Parameters injection is done through setters.&lt;/p&gt;

&lt;p&gt;Here's a concrete example.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;# templates/page/show.html.twig

&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;N9_component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'MyComponent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;example&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'string variable'&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Component/MyComponent/MyComponent.php&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ComponentInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$example&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setExample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$example&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$example&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getTemplateParameters&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'example'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;// src/Component/MyComponent/template.html.twig

&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Displaying custom variable: &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;example&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Moreover, just like every other view in NumberNine, component templates are overridable. The theme you use probably uses components, and you'll probably want to adapt the design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://numberninecms.com/developers/howto/theming/create-a-component.html" rel="noopener noreferrer"&gt;Read more&lt;/a&gt; about components on the documentation page.&lt;/p&gt;
&lt;h2&gt;
  
  
  NumberNine shortcodes
&lt;/h2&gt;

&lt;p&gt;While components are developer-oriented, shortcodes are a user-oriented way to inject templates in the view.&lt;/p&gt;

&lt;p&gt;Also known as BBcodes, shortcodes and have been widely used in forums and CMS for years. They are represented by a string that the user can input in his editor.&lt;/p&gt;

&lt;p&gt;They have a short syntax:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[my_shortcode message="hello"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Or an extended syntax:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[my_shortcode]hello[/my_shortcode]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Extended syntax allows for nested shortcodes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[my_shortcode]
    [my_nested_shortcode message="hello"]
[/my_shortcode]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;NumberNine handles shortcodes as services. Each shortcode has its own class which acts like a controller.&lt;/p&gt;

&lt;p&gt;As an example, we'll analyze this page header:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl82bfj06mjswwjq7cal2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl82bfj06mjswwjq7cal2.jpg" alt="Page header" width="472" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now look at how it's rendered behind the scene:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoa2ps5hqi7a6rmhl1p9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkoa2ps5hqi7a6rmhl1p9.jpg" alt="Rendered shortcodes" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is not the result of a manual input in an editor, although it can. To know more about how it was rendered, see the last section of this article about the page builder.&lt;/p&gt;

&lt;p&gt;Back to our view splitting. To put it simply, this header is composed of 9 controllers and 9 views, with no negative performance impact.&lt;/p&gt;

&lt;p&gt;Let's take the &lt;code&gt;my_account_link&lt;/code&gt; shortcode and see how it's built, as it's a very basic shortcode. Its purpose is to automatically link to the user-defined "My account" page:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @Shortcode(name="my_account_link", label="My Account Link")
 */&lt;/span&gt;
&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAccountLinkShortcode&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractShortcode&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;configureParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;OptionsResolver&lt;/span&gt; &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$resolver&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setDefaults&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'loggedOutText'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Login / Register'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'loggedInText'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'My account'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;processParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$parameters&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'loggedOutText'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'loggedOutText'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s1"&gt;'loggedInText'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$parameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'loggedInText'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;While its template looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight twig"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;N9_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;PAGE_FOR_MY_ACCOUNT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;is_granted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'IS_AUTHENTICATED_REMEMBERED'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;loggedInText&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;trans&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;loggedOutText&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;trans&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now it can be used either by the developer with &lt;code&gt;{{ N9_shortcode('[my_account_link]') }}&lt;/code&gt;, or directly by the user in a text editor with &lt;code&gt;[my_account_link]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's all! Our views can be split in many ways and still keep a high performance. The main controller stays very light, and every partial controllers handle their own responsability. This makes the code highly reusable and easier to use for both developers and users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://numberninecms.com/developers/howto/theming/create-a-shortcode.html" rel="noopener noreferrer"&gt;Read more&lt;/a&gt; about shortcodes on the documentation page.&lt;/p&gt;
&lt;h2&gt;
  
  
  Shortcodes and the page builder
&lt;/h2&gt;

&lt;p&gt;NumberNine's page builder relies on shortcodes to build the view. Each shortcode can be defined as an editable shortcode, which will appear in the page builder's list of available components to the user.&lt;/p&gt;

&lt;p&gt;This will be the topic of an other article. Meanwhile, &lt;a href="https://numberninecms.com/developers/howto/theming/create-a-shortcode.html" rel="noopener noreferrer"&gt;check out the documentation&lt;/a&gt; to see how to build a page builder component with a shortcode.&lt;/p&gt;
&lt;h2&gt;
  
  
  Read more
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/numberninecms" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4530%2F2604e237-cf9a-4a2b-aae3-44bd2117b1a4.png" alt="NumberNine CMS" width="800" height="800"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F680682%2F5a153d1e-ad84-41f5-a6a5-2ddfebe0dd96.jpg" alt="" width="800" height="800"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/numberninecms/symfony-on-steroids-with-numbernine-cms-4no4" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Symfony on steroids with NumberNine CMS&lt;/h2&gt;
      &lt;h3&gt;William Arin for NumberNine CMS ・ Aug 8 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#symfony&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#php&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#cms&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>symfony</category>
      <category>cms</category>
      <category>php</category>
    </item>
    <item>
      <title>Symfony on steroids with NumberNine CMS</title>
      <dc:creator>William Arin</dc:creator>
      <pubDate>Sun, 08 Aug 2021 05:33:17 +0000</pubDate>
      <link>https://dev.to/numberninecms/symfony-on-steroids-with-numbernine-cms-4no4</link>
      <guid>https://dev.to/numberninecms/symfony-on-steroids-with-numbernine-cms-4no4</guid>
      <description>&lt;p&gt;Web agencies and freelancers don't need to waste precious time on project setup and configuration anymore. With &lt;a href="https://numberninecms.com" rel="noopener noreferrer"&gt;NumberNine&lt;/a&gt;'s installer, you'll be able to start working on a Symfony app in seconds.&lt;/p&gt;

&lt;p&gt;Copy/paste this installation one-liner in your terminal, given that you have &lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;Docker installed&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--pull&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;HOST_PWD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;:/srv/app &lt;span class="nt"&gt;-v&lt;/span&gt; /var/run/docker.sock:/var/run/docker.sock &lt;span class="se"&gt;\&lt;/span&gt;
    numberninecms/installer myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Boom! Done.&lt;/p&gt;

&lt;p&gt;One minute later, even without any prior knowledge of Docker, here's what you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The latest Symfony version (&lt;code&gt;symfony/web-skeleton&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The latest NumberNine version&lt;/li&gt;
&lt;li&gt;The latest PHP, MySQL, Nginx, Redis, Maildev and blackfire versions running as Docker containers&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://numberninecms.com/developers/docker.html" rel="noopener noreferrer"&gt;PHP Docker container&lt;/a&gt; with Cachetool,  Composer 2, APCu, Xdebug 3, make, and zsh&lt;/li&gt;
&lt;li&gt;A self-signed SSL certificate for &lt;code&gt;myproject.localhost&lt;/code&gt; and HTTPS access&lt;/li&gt;
&lt;li&gt;A ready-to-use website with all CMS features&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Simplicity in mind
&lt;/h2&gt;

&lt;p&gt;NumberNine is a CMS which focus on simplicity of use, both for the end-users and the developers. It automates most of the tedious steps of setting up a new Symfony project, while also easing the maintenance by the clients in charge of their content.&lt;/p&gt;

&lt;p&gt;For instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have you ever used &lt;code&gt;MakerBundle&lt;/code&gt; to create user, registration form, etc.?&lt;/li&gt;
&lt;li&gt;Have you ever created some CRUD controllers for your entities?&lt;/li&gt;
&lt;li&gt;Have you ever installed &lt;code&gt;VichUploaderBundle&lt;/code&gt; or implemented file upload?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you answered yes to any of these questions, you'll most probably find benefits using NumberNine. All these are core features.&lt;/p&gt;

&lt;p&gt;What's more? It's still a Symfony app, which means that you can develop things that won't interfere with the CMS, the Symfony way. NumberNine acts like an additional CMS layer, so you get the best of both worlds.&lt;/p&gt;
&lt;h2&gt;
  
  
  Some features
&lt;/h2&gt;

&lt;p&gt;You'll find on &lt;a href="https://numberninecms.com/developers/features.html" rel="noopener noreferrer"&gt;this page&lt;/a&gt; an exhaustive list of features, but the most notable are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client-side image resizing with high quality downscaling algorithm&lt;/li&gt;
&lt;li&gt;Granular user management with capabilities assigned to roles&lt;/li&gt;
&lt;li&gt;WYSIWYG extensible page builder&lt;/li&gt;
&lt;li&gt;Shortcodes&lt;/li&gt;
&lt;li&gt;Relationships between entities&lt;/li&gt;
&lt;li&gt;Menu creation&lt;/li&gt;
&lt;li&gt;Easy Twig theming with inheritance (core -&amp;gt; theme -&amp;gt; app)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's MIT license, totally free to use.&lt;/p&gt;

&lt;p&gt;You can star it on Github if you like it.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/numberninecms" rel="noopener noreferrer"&gt;
        numberninecms
      &lt;/a&gt; / &lt;a href="https://github.com/numberninecms/cms" rel="noopener noreferrer"&gt;
        cms
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Core code of NumberNine CMS
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The developer documentation is at &lt;a href="https://numberninecms.com" rel="noopener noreferrer"&gt;https://numberninecms.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus video trailer
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/GcDZgwmVSSM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Read more
&lt;/h2&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/numberninecms" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F4530%2F2604e237-cf9a-4a2b-aae3-44bd2117b1a4.png" alt="NumberNine CMS" width="800" height="800"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F680682%2F5a153d1e-ad84-41f5-a6a5-2ddfebe0dd96.jpg" alt="" width="800" height="800"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/numberninecms/split-your-symfony-views-into-multiple-controllers-with-numbernine-cms-2nj0" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Split your Symfony views into multiple controllers with NumberNine CMS&lt;/h2&gt;
      &lt;h3&gt;William Arin for NumberNine CMS ・ Aug 13 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#symfony&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#cms&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#php&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>symfony</category>
      <category>php</category>
      <category>cms</category>
    </item>
  </channel>
</rss>
