Skip to content

Commit 10166af

Browse files
committed
PoC Grid component
1 parent 08057ed commit 10166af

File tree

20 files changed

+520
-37
lines changed

20 files changed

+520
-37
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace App\Grid\Renderer;
15+
16+
use Sylius\Bundle\ResourceBundle\Grid\Parser\OptionsParserInterface;
17+
use Sylius\Component\Grid\Definition\Action;
18+
use Sylius\Component\Grid\Renderer\BulkActionGridRendererInterface;
19+
use Sylius\Component\Grid\View\GridViewInterface;
20+
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
21+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
22+
use Symfony\Component\HttpFoundation\Request;
23+
use Symfony\Component\HttpFoundation\RequestStack;
24+
use Twig\Environment;
25+
26+
#[AsDecorator(decorates: 'sylius.custom_bulk_action_grid_renderer.twig')]
27+
final class TwigBulkActionGridRenderer implements BulkActionGridRendererInterface
28+
{
29+
public function __construct(
30+
private Environment $twig,
31+
private OptionsParserInterface $optionsParser,
32+
#[Autowire(param: 'sylius.grid.templates.bulk_action')]
33+
private array $bulkActionTemplates = [],
34+
private readonly ?RequestStack $requestStack = null,
35+
) {
36+
}
37+
38+
public function renderBulkAction(GridViewInterface $gridView, Action $bulkAction, $data = null): string
39+
{
40+
$type = $bulkAction->getType();
41+
if (!isset($this->bulkActionTemplates[$type])) {
42+
throw new \InvalidArgumentException(sprintf('Missing template for bulk action type "%s".', $type));
43+
}
44+
45+
$options = $this->optionsParser->parseOptions(
46+
$bulkAction->getOptions(),
47+
$this->requestStack?->getCurrentRequest() ?? new Request(),
48+
$data,
49+
);
50+
51+
return $this->twig->render($this->bulkActionTemplates[$type], [
52+
'grid' => $gridView,
53+
'action' => $bulkAction,
54+
'data' => $data,
55+
'options' => $options,
56+
]);
57+
}
58+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace App\Grid\Renderer;
15+
16+
use Sylius\Bundle\ResourceBundle\Grid\Parser\OptionsParserInterface;
17+
use Sylius\Component\Grid\Definition\Action;
18+
use Sylius\Component\Grid\Definition\Field;
19+
use Sylius\Component\Grid\Definition\Filter;
20+
use Sylius\Component\Grid\Renderer\GridRendererInterface;
21+
use Sylius\Component\Grid\View\GridViewInterface;
22+
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
23+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
24+
use Symfony\Component\HttpFoundation\Request;
25+
use Symfony\Component\HttpFoundation\RequestStack;
26+
use Twig\Environment;
27+
28+
#[AsDecorator(decorates: 'sylius.custom_grid_renderer.twig')]
29+
final class TwigGridRenderer implements GridRendererInterface
30+
{
31+
private GridRendererInterface $gridRenderer;
32+
33+
private Environment $twig;
34+
35+
private OptionsParserInterface $optionsParser;
36+
37+
private array $actionTemplates;
38+
39+
public function __construct(
40+
GridRendererInterface $gridRenderer,
41+
Environment $twig,
42+
OptionsParserInterface $optionsParser,
43+
#[Autowire(param: 'sylius.grid.templates.action')]
44+
array $actionTemplates = [],
45+
private readonly ?RequestStack $requestStack = null,
46+
) {
47+
$this->gridRenderer = $gridRenderer;
48+
$this->twig = $twig;
49+
$this->optionsParser = $optionsParser;
50+
$this->actionTemplates = $actionTemplates;
51+
}
52+
53+
public function render(GridViewInterface $gridView, ?string $template = null): string
54+
{
55+
return $this->gridRenderer->render($gridView, $template);
56+
}
57+
58+
/**
59+
* @param mixed $data
60+
*/
61+
public function renderField(GridViewInterface $gridView, Field $field, $data): string
62+
{
63+
return $this->gridRenderer->renderField($gridView, $field, $data);
64+
}
65+
66+
/**
67+
* @param mixed $data
68+
*/
69+
public function renderAction(GridViewInterface $gridView, Action $action, $data = null): string
70+
{
71+
$type = $action->getType();
72+
if (!isset($this->actionTemplates[$type])) {
73+
throw new \InvalidArgumentException(sprintf('Missing template for action type "%s".', $type));
74+
}
75+
76+
$options = $this->optionsParser->parseOptions(
77+
$action->getOptions(),
78+
$this->requestStack?->getCurrentRequest() ?? new Request(),
79+
$data,
80+
);
81+
82+
return $this->twig->render($this->actionTemplates[$type], [
83+
'grid' => $gridView,
84+
'action' => $action,
85+
'data' => $data,
86+
'options' => $options,
87+
]);
88+
}
89+
90+
public function renderFilter(GridViewInterface $gridView, Filter $filter): string
91+
{
92+
return $this->gridRenderer->renderFilter($gridView, $filter);
93+
}
94+
}

app/Grid/SpeakerGrid.php

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static function getName(): string
3838
public function buildGrid(GridBuilderInterface $gridBuilder): void
3939
{
4040
$gridBuilder
41+
->setLimits([10, 25, 50])
4142
->addFilter(
4243
StringFilter::create('search', ['firstName', 'lastName', 'companyName'])
4344
->setLabel('sylius.ui.search'),
@@ -64,7 +65,12 @@ public function buildGrid(GridBuilderInterface $gridBuilder): void
6465
)
6566
->addActionGroup(
6667
MainActionGroup::create(
67-
CreateAction::create(),
68+
CreateAction::create()
69+
->setOptions([
70+
'link' => [
71+
'route' => 'app_admin_speaker_create',
72+
],
73+
]),
6874
),
6975
)
7076
->addActionGroup(
@@ -82,15 +88,23 @@ public function buildGrid(GridBuilderInterface $gridBuilder): void
8288
],
8389
],
8490
]),
85-
UpdateAction::create(),
86-
DeleteAction::create(),
87-
),
88-
)
89-
->addActionGroup(
90-
BulkActionGroup::create(
91-
DeleteAction::create(),
91+
UpdateAction::create()
92+
->setOptions([
93+
'link' => [
94+
'route' => 'app_admin_speaker_update',
95+
'parameters' => [
96+
'id' => 'resource.id',
97+
],
98+
],
99+
]),
100+
// DeleteAction::create(),
92101
),
93102
)
103+
// ->addActionGroup(
104+
// BulkActionGroup::create(
105+
// DeleteAction::create(),
106+
// ),
107+
// )
94108
;
95109
}
96110

app/Grid/TalkGrid.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,17 @@ public function buildGrid(GridBuilderInterface $gridBuilder): void
9292
CreateAction::create(),
9393
),
9494
)
95-
->addActionGroup(
96-
ItemActionGroup::create(
97-
UpdateAction::create(),
98-
DeleteAction::create(),
99-
),
100-
)
101-
->addActionGroup(
102-
BulkActionGroup::create(
103-
DeleteAction::create(),
104-
),
105-
)
95+
// ->addActionGroup(
96+
// ItemActionGroup::create(
97+
// UpdateAction::create(),
98+
// DeleteAction::create(),
99+
// ),
100+
// )
101+
// ->addActionGroup(
102+
// BulkActionGroup::create(
103+
// DeleteAction::create(),
104+
// ),
105+
// )
106106
;
107107
}
108108

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Sylius Sp. z o.o.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace App\Twig\Component\Grid;
15+
16+
use Pagerfanta\PagerfantaInterface;
17+
use Sylius\Component\Grid\Parameters;
18+
use Sylius\Component\Grid\Provider\ChainProvider;
19+
use Sylius\Component\Grid\Provider\GridProviderInterface;
20+
use Sylius\Component\Grid\View\GridViewFactoryInterface;
21+
use Sylius\Component\Grid\View\GridViewInterface;
22+
use Sylius\TwigHooks\Twig\Component\HookableComponentTrait;
23+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
24+
use Symfony\Component\HttpFoundation\Request;
25+
use Symfony\Component\HttpFoundation\RequestStack;
26+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
27+
use Symfony\UX\LiveComponent\Attribute\LiveAction;
28+
use Symfony\UX\LiveComponent\Attribute\LiveArg;
29+
use Symfony\UX\LiveComponent\Attribute\LiveProp;
30+
use Symfony\UX\LiveComponent\DefaultActionTrait;
31+
32+
#[AsLiveComponent(
33+
name: 'sylius_grid_data_table',
34+
template: '@SyliusBootstrapAdminUi/shared/crud/index/content/grid/data_table.html.twig',
35+
)]
36+
final class DataTableComponent
37+
{
38+
use DefaultActionTrait;
39+
use HookableComponentTrait;
40+
41+
#[LiveProp(writable: true)]
42+
public ?string $grid = null;
43+
44+
#[LiveProp(writable: true)]
45+
public int $page;
46+
47+
/** @var array<string, mixed>|null */
48+
#[LiveProp(writable: true)]
49+
public ?array $criteria = null;
50+
51+
/** @var array<string, string>|null */
52+
#[LiveProp(writable: true)]
53+
public ?array $sorting = null;
54+
55+
#[LiveProp(writable: true)]
56+
public ?int $limit = null;
57+
58+
private ?Request $request;
59+
60+
public function __construct(
61+
#[Autowire(service: ChainProvider::class)]
62+
private readonly GridProviderInterface $gridProvider,
63+
private readonly GridViewFactoryInterface $gridViewFactory,
64+
private readonly RequestStack $requestStack,
65+
) {
66+
$this->request = $this->requestStack->getCurrentRequest();
67+
68+
if (null === $this->request) {
69+
return;
70+
}
71+
72+
$this->page = $this->request->query->getInt('page', 1);
73+
$this->criteria = $this->request->query->all('criteria');
74+
$this->limit = $this->request->query->has('limit') ? $this->request->query->getInt('limit') : null;
75+
}
76+
77+
public function getResources(): GridViewInterface
78+
{
79+
if (null === $this->grid) {
80+
throw new \RuntimeException('No Grid has been passed to the component.');
81+
}
82+
83+
$gridDefinition = $this->gridProvider->get($this->grid);
84+
85+
$config = ['page' => $this->page];
86+
87+
if (null !== $this->criteria) {
88+
$config['criteria'] = $this->criteria;
89+
}
90+
91+
if (null !== $this->sorting) {
92+
$config['sorting'] = $this->sorting;
93+
}
94+
95+
$gridView = $this->gridViewFactory->create(
96+
$gridDefinition,
97+
new Parameters($config),
98+
);
99+
100+
$data = $gridView->getData();
101+
102+
if ($data instanceof PagerfantaInterface) {
103+
$data->setCurrentPage($this->page);
104+
105+
if (null !== $this->limit) {
106+
$data->setMaxPerPage($this->limit);
107+
}
108+
}
109+
110+
return $gridView;
111+
}
112+
113+
#[LiveAction]
114+
public function sortBy(#[LiveArg] string $field, #[LiveArg] string $order): void
115+
{
116+
$this->sorting = [$field => $order];
117+
}
118+
119+
#[LiveAction]
120+
public function updateLimit(#[LiveArg] int $limit): void
121+
{
122+
$this->page = 1;
123+
$this->criteria = null;
124+
$this->sorting = null;
125+
$this->limit = $limit;
126+
}
127+
128+
#[LiveAction]
129+
public function changePage(#[LiveArg] int $page): void
130+
{
131+
$this->page = $page;
132+
}
133+
134+
#[LiveAction]
135+
public function previousPage(): void
136+
{
137+
--$this->page;
138+
}
139+
140+
#[LiveAction]
141+
public function nextPage(): void
142+
{
143+
++$this->page;
144+
}
145+
}

assets/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
import './bootstrap.js';
12
import './scripts/statistics_chart.js';

assets/bootstrap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { startStimulusApp } from '@symfony/stimulus-bundle';
2+
3+
const app = startStimulusApp();
4+
// register any custom, 3rd party controllers here
5+
// app.register('some_controller_name', SomeImportedController);

0 commit comments

Comments
 (0)