Skip to content

Commit

Permalink
Add support for binding row data to grid types, and for row_attr option
Browse files Browse the repository at this point in the history
  • Loading branch information
Sander Marechal committed Mar 28, 2024
1 parent c9913c5 commit 8922d92
Show file tree
Hide file tree
Showing 20 changed files with 219 additions and 39 deletions.
26 changes: 26 additions & 0 deletions doc/types/grid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Grid type
============

The base grid type

## Class

`Prezent\Grid\Extension\Core\Type\GridType`

## Options

### `attr`

The HTML attributes for the element that is used to render on the table.

### `row_attr`

The HTML attributes for the element that is used to render on each table row. For every attribute, values between braces
are interpreted as a property path and will be expanded when the attribute is rendered. E.g. an attribute value
of `{name}` will be rendered as `foo` if the `name` property of the row is `'foo'`.

For every attribute you can also supply a callback that returns a value. The callback is passed the row as only parameter.

## Parent type

None
1 change: 1 addition & 0 deletions doc/types/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Grid consist of columns and actions. Both are implemented as grid elements.

* [column](column.md)
* [element](element.md)
* [grid](grid.md)
7 changes: 7 additions & 0 deletions src/BaseGridType.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ public function buildView(GridView $view, array $options = [])
{
}

/**
* {@inheritDoc}
*/
public function bindView(GridView $view, $item)
{
}

/**
* {@inheritDoc}
*/
Expand Down
7 changes: 7 additions & 0 deletions src/BaseGridTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ public function buildView(GridView $view, array $options)
{
}

/**
* {@inheritDoc}
*/
public function bindView(GridView $view, $item)
{
}

/**
* {@inheritDoc}
*/
Expand Down
8 changes: 4 additions & 4 deletions src/ElementView.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ class ElementView implements View
public $name;

/**
* @var array
* @var ResolvedElementType
*/
public $vars = [];
private $type;

/**
* @var View
*/
public $parent;

/**
* @var ResolvedElementType
* @var array
*/
private $type;
public $vars = [];

/**
* Constructor
Expand Down
2 changes: 1 addition & 1 deletion src/Extension/Core/CoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function __construct(PropertyAccessorInterface $accessor, VariableResolve
protected function loadGridTypes()
{
return [
new GridType(),
new GridType($this->resolver),
];
}

Expand Down
33 changes: 32 additions & 1 deletion src/Extension/Core/GridType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Prezent\Grid\BaseGridType;
use Prezent\Grid\GridView;
use Prezent\Grid\VariableResolver;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
Expand All @@ -14,14 +15,33 @@
*/
class GridType extends BaseGridType
{
/**
* @var VariableResolver
*/
private $resolver;

/**
* Constructor
*
* @param VariableResolver $resolver
*/
public function __construct(VariableResolver $resolver)
{
$this->resolver = $resolver;
}

/**
* {@inheritDoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults(['attr' => []])
->setDefaults([
'attr' => [],
'row_attr' => [],
])
->setAllowedTypes('attr', 'array')
->setAllowedTypes('row_attr', 'array')
;
}

Expand All @@ -31,6 +51,17 @@ public function configureOptions(OptionsResolver $resolver)
public function buildView(GridView $view, array $options = [])
{
$view->vars['attr'] = $options['attr'];
$view->vars['row_attr'] = $options['row_attr'];
}

/**
* {@inheritDoc}
*/
public function bindView(GridView $view, $item)
{
foreach ($view->vars['row_attr'] as $key => $value) {
$view->vars['row_attr'][$key] = $this->resolver->resolve($value, $item);
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Grid.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public function createView()
$columnViews = [];
$actionViews = [];

$view = new GridView();
$view = new GridView($this->type);
$this->type->buildView($view, $this->options);

foreach ($this->columns as $name => $column) {
Expand Down
9 changes: 9 additions & 0 deletions src/GridTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ public function buildGrid(GridBuilder $builder, array $options = []);
*/
public function buildView(GridView $view, array $options);

/**
* Bind an item to the view
*
* @param GridView $view
* @param mixed $item
* @return void
*/
public function bindView(GridView $view, $item);

/**
* Get the grid type name of the extended type
*
Expand Down
19 changes: 18 additions & 1 deletion src/GridView.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
*/
class GridView implements View
{
/**
* @var ResolvedGridType
*/
private $type;

/**
* @var ViewCollection
*/
Expand All @@ -30,9 +35,21 @@ class GridView implements View
* @param array $columns
* @param array $actions
*/
public function __construct(array $columns = [], array $actions = [])
public function __construct(ResolvedGridType $type, array $columns = [], array $actions = [])
{
$this->type = $type;
$this->columns = new ViewCollection($columns);
$this->actions = new ViewCollection($actions);
}

/**
* Bind an item to the view
*
* @param mixed $item
* @return void
*/
public function bind($item)
{
$this->type->bindView($this, $item);
}
}
20 changes: 20 additions & 0 deletions src/ResolvedGridType.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,26 @@ public function buildView(GridView $view, array $options = [])
}
}

/**
* Bind an item to the view
*
* @param GridView $view
* @param mixed $item
* @return void
*/
public function bindView(GridView $view, $item)
{
if ($this->parent) {
$this->parent->bindView($view, $item);
}

$this->innerType->bindView($view, $item);

foreach ($this->typeExtensions as $typeExtension) {
$typeExtension->bindView($view, $item);
}
}

/**
* Get the optionsResolver
*
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/views/grid/grid.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{%- endblock grid -%}

{%- block grid_header_row -%}
<tr>
<tr {% with {attr: row_attr} %}{{ block('grid_attributes') }}{% endwith %}>
{% for column in grid.columns %}
{{- grid_header_column(column) -}}
{% endfor %}
Expand Down
4 changes: 3 additions & 1 deletion src/Twig/GridExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Prezent\Grid\Twig;

use Prezent\Grid\Twig\Node\RenderBlockNode;
use Prezent\Grid\Twig\Node\RenderGridBlockNode;
use Prezent\Grid\Twig\Node\RenderItemBlockNode;
use Prezent\Grid\Twig\TokenParser\GridThemeTokenParser;
use Twig\Environment;
Expand All @@ -25,10 +26,11 @@ class GridExtension extends AbstractExtension implements RuntimeExtensionInterfa
public function getFunctions(): array
{
$blockOptions = ['node_class' => RenderBlockNode::class, 'is_safe' => ['html'], ''];
$blockGridOptions = ['node_class' => RenderGridBlockNode::class, 'is_safe' => ['html']];
$blockItemOptions = ['node_class' => RenderItemBlockNode::class, 'is_safe' => ['html']];

return [
new TwigFunction('grid', null, $blockItemOptions),
new TwigFunction('grid', null, $blockGridOptions),
new TwigFunction('grid_header_row', null, $blockOptions),
new TwigFunction('grid_header_column', null, $blockOptions),
new TwigFunction('grid_header_widget', null, $blockOptions),
Expand Down
26 changes: 13 additions & 13 deletions src/Twig/GridRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,16 @@ public function setTheme(View $view, $themes)
* @param GridView|ElementView $view
* @param mixed $item
* @param array $variables
* @param bool $bind
* @return string
*/
public function renderBlock($name, View $view, $item = null, array $variables = [])
public function renderBlock($name, View $view, $item = null, array $variables = [], $bind = false)
{
// Environment stacking
//
// Every nested call to renderBlock adds the variables to the
// twig rendering environment for that block
$variableStack = $this->getVariableStack($view, $item);
$variableStack = $this->getVariableStack($view, $item, $bind);
$variables = array_merge($variableStack->top(), $variables);
$variableStack->push($variables);

Expand Down Expand Up @@ -189,9 +190,10 @@ private function findThemeForBlock($name, View $view)
*
* @param GridView|ElementView $view
* @param mixed $item
* @param bool $bind
* @return \SplStack
*/
private function getVariableStack(View $view, $item)
private function getVariableStack(View $view, $item, $bind = false)
{
if (!$this->variableStack->contains($view)) {
$this->variableStack->attach($view, new \SplStack());
Expand All @@ -203,21 +205,19 @@ private function getVariableStack(View $view, $item)
}
}

$variables = [];
$variables = $view->vars;

if ($item && $bind) {
$boundView = clone $view;
$boundView->bind($item);
$variables = $boundView->vars;
}

if ($view instanceof GridView) {
$variables = array_merge(['grid' => $view, 'data' => $item], $view->vars);
$variables = array_merge(['grid' => $view, 'data' => $item], $variables);
}

if ($view instanceof ElementView) {
if ($item) {
$boundView = clone $view;
$boundView->bind($item);
$variables = $boundView->vars;
} else {
$variables = $view->vars;
}

$variables = array_merge(['column' => $view, 'item' => $item], $variables);
}

Expand Down
33 changes: 33 additions & 0 deletions src/Twig/Node/RenderGridBlockNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Prezent\Grid\Twig\Node;

use Prezent\Grid\Twig\GridRenderer;
use Twig\Compiler;
use Twig\Node\Expression\FunctionExpression;

/**
* Compile a grid block
*
* @see FunctionExpression
* @author Sander Marechal
*/
class RenderGridBlockNode extends FunctionExpression
{
public function compile(Compiler $compiler): void
{
$compiler->addDebugInfo($this);
$arguments = iterator_to_array($this->getNode('arguments'));

$compiler
->write('$this->env->getRuntime(\''. GridRenderer::class . '\')->renderBlock(')
->raw('\''.$this->getAttribute('name').'\'');

foreach ($arguments as $argument) {
$compiler->raw(', ');
$compiler->subcompile($argument);
}

$compiler->raw(')');
}
}
24 changes: 19 additions & 5 deletions src/Twig/Node/RenderItemBlockNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,27 @@ public function compile(Compiler $compiler): void

$compiler
->write('$this->env->getRuntime(\''. GridRenderer::class . '\')->renderBlock(')
->raw('\''.$this->getAttribute('name').'\'');
->raw('\''.$this->getAttribute('name').'\', ')
->subcompile($arguments[0]);

foreach ($arguments as $argument) {
$compiler->raw(', ');
$compiler->subcompile($argument);
// item
if (isset($arguments[1])) {
$compiler
->raw(', ')
->subcompile($arguments[1]);
} else {
$compiler->raw(', null');
}

$compiler->raw(')');
// variables
if (isset($arguments[2])) {
$compiler
->raw(', ')
->subcompile($arguments[2]);
} else {
$compiler->raw(', []');
}

$compiler->raw(', true)');
}
}
Loading

0 comments on commit 8922d92

Please sign in to comment.