Answers.Body: <p>It's not bad the way you've done it, in my opinion. However I'd probably use an <code>embed</code> instead of an <code>include</code> - that way you can pass in a block of content without having to use <code>set...endset</code>, which sometimes comes with auto-escaping issues, and it just feels a bit cleaner to me:</p>
  <pre class="lang-twig prettyprint-override"><code>{# ==================================
  Calling template
  ===================================== #}
  
  {% embed '_ui/components/grid/grid' with {    
      gridCols: gridCols,
      additionalClass: 'c-teaser teasergroup-' ~ variant,
  } only %}
      {% block gridItems %}
          &lt;p&gt;All your stuff here&lt;/p&gt;
      {% endblock %}
  {% endembed %}
  
  {# ==================================
  _ui/components/grid/grid
  ===================================== #}
  
  {% set gridColsDefault = gridCols[0]|default(1) %}
  {% set inheritGridColsSmall = gridCols[1]|default(gridColsDefault) %}
  ...
  
  &lt;div class=&quot;row row-cols-...&quot;&gt;
      {% block gridItems %}{% endblock %}
      {# or just {{ block('gridItems') }} if you don't need any default content. #}
  &lt;/div&gt;
  </code></pre>
  <p><a href="https://twig.symfony.com/doc/3.x/tags/embed.html" rel="nofollow noreferrer">https://twig.symfony.com/doc/3.x/tags/embed.html</a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-10-16T09:25:48.583Z
Answers.Text: Ahhh ... I see.
  
  Thank you, James, for explanation!
Answers.UserDisplayName: Marc 
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-10-14T14:19:49.293Z
Answers.LastActivityDate: 2023-10-15T09:20:47.970Z
Answers.LastEditDate: 2023-10-15T09:20:47.970Z
Answers.UserDisplayName: James Smith
Body: <p>First of all: My solution works ... I can not see any problems.<br />
  But I'm very unsure whether my code ist a dirty hack or not.</p>
  <p>Please don't care about details in my code ... I'm uncertain because:<br />
  There is a lot of logic inside <code>{% set teaserItems %}</code>.</p>
  <p>Is there a &quot;better&quot; or &quot;cleaner&quot; or &quot;more performant&quot; solution for this?<br />
  If not: I'm fine. :)</p>
  <pre><code>{# Builds the individual teasers for the grid. #}
  {% set teaserItems %}
      {% for item in items %}
  
          {% set teaser = {
              image: null,
              heading: null,
              text: null,
              button: null,
              link: null,
              overlay: null,
          } %}
  
          {# Creates the data structure on Teaser or Entry. #}
          {% switch item.type.handle %}
  
              {% case 'btcTeaserTeaser' %} {# Teaser #}
  
                  {% if item.hasDescendants() %}
                      {% set teaser = teaser|merge({
                          image: {
                              image: item.children[0].assetImage,
                              altText: item.children[0].assetAltText
                          },
                      }) %}
                  {% endif %}
  
                  {% if item.heading %}
                      {% set teaser = teaser|merge({
                          heading: {
                              text: item.heading,
                              level: 4
                          },
                      }) %}
                  {% endif %}
  
                  {% if item.richTextSimple %}
                      {% set teaser = teaser|merge({
                          text: item.richTextSimple,
                      }) %}
                  {% endif %}
  
                  {% if item.linkField.getUrl() %}
                      {% set teaser = teaser|merge({
                          button: item.buttonText|default(_globals.get('moreText')),
                          link: {
                              url: item.linkField.getUrl(),
                              target: item.linkField.target
                          },
                      }) %}
                  {% endif %}
  
              {% case 'btcTeaserEntry' %} {# Entry #}
  
                  {% set entry = item.teaserEntryPreview.one() %}
  
                  {% if entry.entryPreviewImage %}
                      {% set teaser = teaser|merge({
                          image: {
                              image: entry.entryPreviewImage,
                              altText: entry.assetAltText
                          },
                      }) %}
                  {% endif %}
  
                  {% if entry.entryPreviewHeading %}
                      {% set teaser = teaser|merge({
                          heading: {
                              text: entry.entryPreviewHeading,
                              level: 4
                          },
                      }) %}
                  {% endif %}
  
                  {% if entry.entryPreviewText %}
                      {% set teaser = teaser|merge({
                          text: entry.entryPreviewText,
                      }) %}
                  {% endif %}
  
                  {% if entry.url %}
                      {% set teaser = teaser|merge({
                          button: item.buttonText|default(_globals.get('moreText')),
                          link: {
                              url: entry.url,
                          },
                      }) %}
                  {% endif %}
  
          {% endswitch %}
  
          {# For teaser variant &quot;Overlay&quot;, both BockTypes have this field in common. #}
          {% if item.teaserOverlay %}
              {% set teaser = teaser|merge({
                  overlay: item.teaserOverlay,
              }) %}
          {% endif %}
  
          {# Creates the teaser with the data structure. #}
          {# variant: Variant of the teaser and directory in the path to the template. #}
          &lt;div id=&quot;&quot; class=&quot;col {{ additionalClass|default }}&quot;&gt;
              {% include '_ui/components/teaser/variant/' ~ variant ~ '/teaser-item.twig' with {
                  id: pid ~ '-' ~ loop.index,
                  variant: 'teaser-' ~ variant,
                  teaser: teaser,
                  colorSet: item.colorSet,
                  ratio: ratio,
                  additionalClass: 'h-100',
              } only %}
          &lt;/div&gt;
  
      {% endfor %}
  {% endset %}
  
  {# Build the grid with the teasers. #}
  {% include '_ui/components/grid/grid' with {
      gridItems: teaserItems,
      gridCols: gridCols,
      additionalClass: 'c-teaser teasergroup-' ~ variant,
  } only %}
  </code></pre>
  <p><strong>_ui/components/grid/grid</strong></p>
  <pre><code>{# inheritance #}
  {% set gridColsDefault = gridCols[0]|default(1) %}
  {% set inheritGridColsSmall = gridCols[1]|default(gridColsDefault) %}
  {% set inheritGridColsMedium = gridCols[2]|default(inheritGridColsSmall) %}
  {% set inheritGridColsLarge = gridCols[3]|default(inheritGridColsMedium) %}
  {% set inheritGridColsXLarge = gridCols[4]|default(inheritGridColsLarge) %}
  {% set inheritGridColsXxLarge = gridCols[5]|default(inheritGridColsXLarge) %}
  
      &lt;div class=&quot;row row-cols-{{ gridColsDefault }} row-cols-sm-{{ inheritGridColsSmall }} row-cols-md-{{ inheritGridColsMedium }} 
                  row-cols-lg-{{ inheritGridColsLarge }} row-cols-xl-{{ inheritGridColsXLarge }} row-cols-xxl-{{ inheritGridColsXxLarge }}
                  g-3 {{ additionalClass|default }}&quot;&gt;
      
          {{ gridItems }}
      
      &lt;/div&gt;
  </code></pre>
  
Tags: <templating>
Title: twig: loop and switch within set -> dirty code or pragmatic solution
ThreadText: # twig: loop and switch within set -> dirty code or pragmatic solution
  
  (Asked by: username_0 on 2023-10-13)
  
  First of all: My solution works ... I can not see any problems.  
  But I'm very unsure whether my code ist a dirty hack or not.
  
  Please don't care about details in my code ... I'm uncertain because:  
  There is a lot of logic inside `{% set teaserItems %}`.
  
  Is there a "better" or "cleaner" or "more performant" solution for this?  
  If not: I'm fine. :)
  
  ```
  {# Builds the individual teasers for the grid. #}
  {% set teaserItems %}
      {% for item in items %}
  
          {% set teaser = {
              image: null,
              heading: null,
              text: null,
              button: null,
              link: null,
              overlay: null,
          } %}
  
          {# Creates the data structure on Teaser or Entry. #}
          {% switch item.type.handle %}
  
              {% case 'btcTeaserTeaser' %} {# Teaser #}
  
                  {% if item.hasDescendants() %}
                      {% set teaser = teaser|merge({
                          image: {
                              image: item.children[0].assetImage,
                              altText: item.children[0].assetAltText
                          },
                      }) %}
                  {% endif %}
  
                  {% if item.heading %}
                      {% set teaser = teaser|merge({
                          heading: {
                              text: item.heading,
                              level: 4
                          },
                      }) %}
                  {% endif %}
  
                  {% if item.richTextSimple %}
                      {% set teaser = teaser|merge({
                          text: item.richTextSimple,
                      }) %}
                  {% endif %}
  
                  {% if item.linkField.getUrl() %}
                      {% set teaser = teaser|merge({
                          button: item.buttonText|default(_globals.get('moreText')),
                          link: {
                              url: item.linkField.getUrl(),
                              target: item.linkField.target
                          },
                      }) %}
                  {% endif %}
  
              {% case 'btcTeaserEntry' %} {# Entry #}
  
                  {% set entry = item.teaserEntryPreview.one() %}
  
                  {% if entry.entryPreviewImage %}
                      {% set teaser = teaser|merge({
                          image: {
                              image: entry.entryPreviewImage,
                              altText: entry.assetAltText
                          },
                      }) %}
                  {% endif %}
  
                  {% if entry.entryPreviewHeading %}
                      {% set teaser = teaser|merge({
                          heading: {
                              text: entry.entryPreviewHeading,
                              level: 4
                          },
                      }) %}
                  {% endif %}
  
                  {% if entry.entryPreviewText %}
                      {% set teaser = teaser|merge({
                          text: entry.entryPreviewText,
                      }) %}
                  {% endif %}
  
                  {% if entry.url %}
                      {% set teaser = teaser|merge({
                          button: item.buttonText|default(_globals.get('moreText')),
                          link: {
                              url: entry.url,
                          },
                      }) %}
                  {% endif %}
  
          {% endswitch %}
  
          {# For teaser variant "Overlay", both BockTypes have this field in common. #}
          {% if item.teaserOverlay %}
              {% set teaser = teaser|merge({
                  overlay: item.teaserOverlay,
              }) %}
          {% endif %}
  
          {# Creates the teaser with the data structure. #}
          {# variant: Variant of the teaser and directory in the path to the template. #}
          <div id="" class="col {{ additionalClass|default }}">
              {% include '_ui/components/teaser/variant/' ~ variant ~ '/teaser-item.twig' with {
                  id: pid ~ '-' ~ loop.index,
                  variant: 'teaser-' ~ variant,
                  teaser: teaser,
                  colorSet: item.colorSet,
                  ratio: ratio,
                  additionalClass: 'h-100',
              } only %}
          </div>
  
      {% endfor %}
  {% endset %}
  
  {# Build the grid with the teasers. #}
  {% include '_ui/components/grid/grid' with {
      gridItems: teaserItems,
      gridCols: gridCols,
      additionalClass: 'c-teaser teasergroup-' ~ variant,
  } only %}
  
  ```
  
  **\_ui/components/grid/grid**
  
  ```
  {# inheritance #}
  {% set gridColsDefault = gridCols[0]|default(1) %}
  {% set inheritGridColsSmall = gridCols[1]|default(gridColsDefault) %}
  {% set inheritGridColsMedium = gridCols[2]|default(inheritGridColsSmall) %}
  {% set inheritGridColsLarge = gridCols[3]|default(inheritGridColsMedium) %}
  {% set inheritGridColsXLarge = gridCols[4]|default(inheritGridColsLarge) %}
  {% set inheritGridColsXxLarge = gridCols[5]|default(inheritGridColsXLarge) %}
  
      <div class="row row-cols-{{ gridColsDefault }} row-cols-sm-{{ inheritGridColsSmall }} row-cols-md-{{ inheritGridColsMedium }} 
                  row-cols-lg-{{ inheritGridColsLarge }} row-cols-xl-{{ inheritGridColsXLarge }} row-cols-xxl-{{ inheritGridColsXxLarge }}
                  g-3 {{ additionalClass|default }}">
      
          {{ gridItems }}
      
      </div>
  
  ```
  
  **Tags:** templating
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2023-10-14. Score: 1
  
  It's not bad the way you've done it, in my opinion. However I'd probably use an `embed` instead of an `include` - that way you can pass in a block of content without having to use `set...endset`, which sometimes comes with auto-escaping issues, and it just feels a bit cleaner to me:
  
  ```twig
  {# ==================================
  Calling template
  ===================================== #}
  
  {% embed '_ui/components/grid/grid' with {    
      gridCols: gridCols,
      additionalClass: 'c-teaser teasergroup-' ~ variant,
  } only %}
      {% block gridItems %}
          <p>All your stuff here</p>
      {% endblock %}
  {% endembed %}
  
  {# ==================================
  _ui/components/grid/grid
  ===================================== #}
  
  {% set gridColsDefault = gridCols[0]|default(1) %}
  {% set inheritGridColsSmall = gridCols[1]|default(gridColsDefault) %}
  ...
  
  <div class="row row-cols-...">
      {% block gridItems %}{% endblock %}
      {# or just {{ block('gridItems') }} if you don't need any default content. #}
  </div>
  
  ```
  
  <https://twig.symfony.com/doc/3.x/tags/embed.html>
  
  > **Comments:**
  > **username_0**: Ahhh ... I see.  Thank you, username_1, for explanation!  
  
  ---
  
  