Drag and drop-able "components"
I'm not totally sure I fully understand your question, but what you're describing definitely sounds like a job for Matrix.

Unfortunately I have no experience with Silverstripe, so I can't make any comparisons to Craft or Matrix and similar functionality in that system, but as a basic overview of what Matrix is and does, I'll just quote the official docs:


  Matrix fields allow you to create multiple blocks of content within a single field.


Basically, you can think of a Matrix field as a glorified table of repeating content. If you ever worked with WordPress and Advanced Custom Fields, Matrix is basically the same thing as the Flexible Content field in ACF.

Matrix fields have many use cases, but using them as "layout" builders in modular design is very common, and is (as far as I can tell) what you're looking to achieve here.

A block type in a Matrix field is basically a self contained set of fields. A block is an instance of a block type. After configuring a Matrix field with a selection of different block types (or layouts) such as a WYSYWIG editor, an image gallery, an embedded video, a news feed etc. When a user is editing the entry, he or she can add one or several blocks of each type to the entry, in any order.

For your use case (such as I understand it) let's say you create a Matrix field with the handle pageLayout, and add the following block types to it:


Advert (handle advert)
Customer list (handle customerList)
Text and image (handle textAndImage)


For each block type, you add the fields you need. Since the block types are sandboxed, you can have a field with the same handles in more than one block type, e.g. an image field called image or a text field called text in both the advert and textAndImage blocks.

It's difficult to advise on specific fields you'd need for the three block types above, but for your advert block type you might need a Plain Text field for URL and an Assets field called image. Assuming your customers are Users or even Entries you might need a Users or Entries field for your customerList block type, and the textAndImage field should probably have a Rich Text and an Assets field. You also might want to give the content editor the option to add a custom heading to each block, in which case you could add a PlainText heading field to each block type.

When you edit your entries, you can create one or several of each of the three block types. You can reorder blocks you already created, remove single blocks or add new blocks of either type above or below existing blocks.

To render your Matrix content, you'll usually work with a Twig for loop to run through all your blocks and render their data.

Using the {% switch %} tag to render different code based on the block type is a good way to keep things readable and clean – here's an example where all the individual block type markup is inline:

{% for block in entry.pageLayout %}
    {# Inside here, `block` refers to a single block in the Matrix field #}
    {% switch block.type %}
        {% case 'advert' %}
            &lt;figure class="advert"&gt;
                {% set image = block.image.first() %}
                &lt;img src="{{ image.getUrl() }}" /&gt;
            &lt;/figure&gt;
        {% case 'customerList' %}
            &lt;ul class="customerList"&gt;
                {% set customers = block.customers %}
                {% for customer in customers %}
                    &lt;li&gt;{{ customer.name }}&lt;/li&gt;
                {% endfor %}
           &lt;/ul&gt;
        {% case 'textAndImage' %}
           {% set image = block.image.first() %}
           &lt;img src="{{ image.getUrl() }}" /&gt;
           &lt;p&gt;{{ block.text }}&lt;/p&gt;
    {% endswitch %}
{% endfor %}


Of course, to keep things even more tidy, you might opt for an approach using template partials, where you put the markup for each block type in their own template (e.g. templates/blocks/advert.html), and use the {% include %} tag to render them inside the Matrix for loop:

{% for block in entry.pageLayout %}
    {% switch block.type %}
        {% case 'advert' %}
            {% include 'blocks/advert' %}
        {% case 'customerList' %}
            {% include 'blocks/customerList' %}
        {% case 'textAndImage' %}
           {% include 'blocks/textAndImage' %}
    {% endswitch %}
{% endfor %}


In fact, if you name your templates after your block type handles, you may get away with not having a {% switch %} tag at all:

{% for block in entry.pageLayout %}
    {% include 'blocks/'~block.type %}
{% endfor %}