# Custom renderer variables

**Magento 2 by default allows rendering child blocks via methods like `getChildHtml()` and any block via `getBlockHtml()`. Still, Loki has added various template variables to perform similar tasks: `$blockRenderer`, `$childRenderer` and `$templateRenderer`. This ADR explains why.**

## `$childRenderer`
The regular `$block->getChildHtml()` call allows you to render a block that is a child to the current block. This assumes that the child has been defined in the XML layout and that it has been given a proper `name` or `as` argument.

```php
echo $block->getChildHtml('example');
```

However, if you want to pass data to the child block, it requires a bit more work:

```php
echo $block->getChildBlock('example')->addData(['foo' => 'bar'])->toHtml();
```

With the `$childRenderer`, this becomes a tiny bit shorter:

```php
echo $childRenderer->html($block, 'example', ['foo' => 'bar']);
```

However, underneath some extra tricks are added. The first argument `$block` is passed on to the child as a property `ancestor_block`, so that within the child you can refer to the ancestor block as follows (which is actually identical to the Magento core its `$block->getParent()`):

```php
$block->getAncestorBlock();
```

There is also an `uniq_id` property created on the child block, which serves as the base for a DOM ID:

```php
$block->getUniqId();
```

The layout name of the child is automatically derived from the parent name, so that the hierarchy of XML layout names always makes sense. For instance, if the parent block is called `loki.example-parent` and the child alias is `example-child`, the XML layout name of the child becomes `loki.example-parent.example-child`. 

```php
$block->getNameInLayout(); // loki.example-parent.example-child
```

If a child block is called upon in a loop, the XML layout name is usually suffixed with an incrementing counter.

```php
$block->getNameInLayout(); // loki.example-parent.block2
```

If the parent block has a property `view_model`, this ViewModel becomes available to the child as well:

```php
$block->getViewModel(); // for example \Loki\Components\Component\ComponentViewModelInterface
```

Because of these tricks, the `$childRenderer` is found frequently in the code. However, there are also cases where `$block->getChildHtml()` is found to be a better option - mainly, if the data of the parent should not be added to the child to avoid confusion.

## `$blockRenderer`
The `$blockRenderer` is very similar to the `$childRenderer`, except it is given a full block name instead:

```php
echo $childRenderer->html($block, 'loki.example-block', ['foo' => 'bar']);
```

The same variables are added to the child block: `view_model`, `uniq_id` and `ancestor_block` - as explained for the `$childRenderer` above. 

## `$templateRenderer`
The `$templateRenderer` is very similar to both the `$blockRenderer` and the `$childRenderer`, except it is given a template file instead:

```php
echo $templateRenderer->html($block, 'Loki_Example::example.phtml', ['foo' => 'bar']);
```

The same variables are added to the child block: `view_model`, `uniq_id` and `ancestor_block` - as explained for the `$childRenderer` above. Just like with the `$childRenderer`, an alias is generated on the fly as well.

## Why need a first argument `$block`?
In all of the renderer calls, the first argument `$block` should refer to the block instance that you make the call from. It is cluttering the code a bit, so we tried to remove it and replace it with some other structure. Unfortunately, this failed.

The various renderer classes are added via an observer to each block. They are singletons and therefore should not retain state. We tried this and this caused issues with one child block overriding the parent block data, before a second child block was called. Obviously. Turning these classes into non-singletons (either with `shared=true` or by using factories) worked perfectly fine. However, this led to 3 objects being created for every block instance and was not very good for performance.

Because of this, we settled for a more explicit syntax with the `$block` being the first (required) argument for each call.
