Skip to content

Commit 2cd3695

Browse files
Add "AddIf" options (#16)
Add "syfmony/security-bundle" to dependencies Add "AddIf" option to columns Add "AddIf" option to action buttons Add .php-version with version 7.4 Add "attr" option to action buttons
1 parent 8d5e9ab commit 2cd3695

14 files changed

Lines changed: 158 additions & 35 deletions

.php-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
7.4

README.md

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Inspired by [SgDatatablesBundle](https://github.com/stwe/DatatablesBundle).
2727
7. [Common Use-Cases](#common-use-cases)
2828
1. [Custom Doctrine Queries](#custom-doctrine-queries)
2929
2. [Detail View](#detail-view)
30+
3. [Use Icons as action buttons](#use-icons-as-action-buttons)
3031
8. [Contributing](#contributing)
3132

3233
## Features
@@ -155,6 +156,10 @@ class UserTable extends HelloBootstrapTable
155156
->add('department.name', TextColumn::class, array(
156157
'title' => 'Department',
157158
'emptyData' => 'No Department',
159+
'addIf' => function() {
160+
// In this callback it is decided if the column will be rendered.
161+
return $this->security->isGranted('ROLE_DEPARTMENT_VIEWER');
162+
}
158163
))
159164
->add("isActive", BooleanColumn::class, array(
160165
'title' => 'is active',
@@ -180,7 +185,11 @@ class UserTable extends HelloBootstrapTable
180185
array(
181186
'displayName' => 'edit',
182187
'routeName' => 'edit_user',
183-
'classNames' => 'btn btn-xs btn-warning'
188+
'classNames' => 'btn btn-xs btn-warning',
189+
'addIf' => function() {
190+
// In this callback it is decided if the button will be rendered.
191+
return $this->security->isGranted('ROLE_USER_EDITOR');
192+
}
184193
)
185194
)
186195
));
@@ -262,6 +271,7 @@ Represents column with text. With formatter you can create complex columns.
262271
| sort | Closure / null | null | custom sort query callback (see example) |
263272
| filter | Closure / null | null | custom filter query callback (see example) |
264273
| data | Closure / null | null | custom data callback (see example) |
274+
| addIf | Closure | ` function() {return true;}` | In this callback it is decided if the column will be rendered. |
265275
| align | string / null | null | Indicate how to align the column data. `'left'`, `'right'`, `'center'` can be used. |
266276
| halign | string / null | null | Indicate how to align the table header. `'left'`, `'right'`, `'center'` can be used. |
267277
| valign | string / null | null | Indicate how to align the cell data. `'top'`, `'middle'`, `'bottom'` can be used. |
@@ -410,34 +420,44 @@ All Options of TextColumn
410420
#### Example
411421

412422
```php
413-
->add("actions", ActionColumn::class, array( // key "actions" can be chosen freely.
423+
->add("actions", ActionColumn::class, array( // key "actions" can be chosen freely but must be unique in the table
414424
'title' => 'Actions',
415425
'width' => 120, //optional
416426
'buttons' => array(
417427
array(
418428
'displayName' => 'show',
419429
'routeName' => 'show_user',
420-
'additionalClassNames' => 'btn-success'
430+
'additionalClassNames' => 'btn-success',
431+
'attr' => array(
432+
'title' => 'Show',
433+
// any number of other attributes
434+
)
421435
),
422436
array(
423437
'displayName' => 'edit',
424438
'routeName' => 'edit_user',
425439
// 'classNames' => 'btn btn-xs' (see below for more information)
426-
'additionalClassNames' => 'btn-warning'
440+
'additionalClassNames' => 'btn-warning',
441+
'addIf' => function() {
442+
// In this callback it is decided if the button will be rendered.
443+
return $this->security->isGranted('ROLE_ADMIN');
444+
}
427445
)
428446
)
429447
))
430448
```
431449

432450
#### ActionButtons
433451

434-
| Option | Type | Default | Description |
435-
| -------------------- | ------ | ----------- | ------------------------------------------------------------ |
436-
| displayName | string | "" | label of button |
437-
| routeName | string | "" | route name |
438-
| routeParams | array | array("id") | Array of property value names for the route parameters. By default is `id` set. |
439-
| classNames | string | "" | CSS class names which added directly to the `a` element. Overrides default class names from YAML config. |
440-
| additionalClassNames | string | "" | You can set default class names in YAML config. Then you can add additional class names to the button without override the default config. |
452+
| Option | Type | Default | Description |
453+
| -------------------- | ------- | ---------------------------- | ------------------------------------------------------------ |
454+
| displayName | string | "" | label of button |
455+
| routeName | string | "" | route name |
456+
| routeParams | array | ["id"] | Array of property value names for the route parameters. By default is `id` set. |
457+
| classNames | string | "" | CSS class names which added directly to the `a` element. Overrides default class names from YAML config. |
458+
| additionalClassNames | string | "" | You can set default class names in YAML config. Then you can add additional class names to the button without override the default config. |
459+
| attr | array | [ ] | Array of any number of attributes formatted as HTML attributes. The array `["title" => "Show"]` is formatted as `title="Show"`. The `href` and `class` attributes are created by the other options and should not be defined here. |
460+
| addIf | Closure | ` function() {return true;}` | In this callback it is decided if the button will be rendered. |
441461

442462
#### YAML Example
443463

@@ -816,6 +836,36 @@ window.detailViewFormatter = function (index, row, element) {
816836

817837
Alternative you can of course create your HTML with JavaScript inside the formatter.
818838

839+
### Use Icons as action buttons
840+
841+
To save space in the table, it makes sense to use icons instead of written out buttons. This is easily possible by using HTML instead of a word in the ` displayName` option of the action buttons.
842+
843+
```php
844+
// src/HelloTable/UserTable.php
845+
846+
class UserTable extends HelloBootstrapTable
847+
{
848+
...
849+
850+
protected function buildColumns(ColumnBuilder $builder, $options)
851+
{
852+
$builder
853+
// more columns ...
854+
->add("actions", ActionColumn::class, array(
855+
'title' => 'Actions',
856+
'buttons' => array(
857+
array(
858+
'displayName' => "<i class='fa fa-eye'></i>", // <-- e.g. FontAwesome icon
859+
'routeName' => 'show_user',
860+
'additionalClassNames' => 'btn-success',
861+
),
862+
// more buttons ...
863+
)
864+
));
865+
}
866+
}
867+
```
868+
819869

820870

821871
## Contributing

assets/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ $(function () {
3131

3232
for (let i = 0; i < value.length; i++) {
3333
buttons.push(
34-
`<a href="${value[i].route}" class="${value[i].classNames}">${value[i].displayName}</a>`
34+
`<a href="${value[i].route}" class="${value[i].classNames}" ${value[i].attr}>${value[i].displayName}</a>`
3535
);
3636
}
3737

composer.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
},
1919
"require": {
2020
"php": ">=7.2.5",
21-
"symfony/property-access": "^4.4|^5.0",
22-
"sensio/framework-extra-bundle": "^5.1",
23-
"symfony/options-resolver": "^4.4|^5.0",
2421
"ext-json": "*",
2522
"doctrine/common": "^2.6|^3.0",
26-
"doctrine/doctrine-bundle": "^2.1|^3.0",
2723
"doctrine/orm": "^2.6.3",
28-
"symfony/twig-bundle": "^4.4|^5.0"
24+
"sensio/framework-extra-bundle": "^5.1",
25+
"symfony/property-access": "^4.4|^5.0",
26+
"symfony/security-bundle": "^4.4|^5.0",
27+
"symfony/twig-bundle": "^4.4|^5.0",
28+
"symfony/options-resolver": "^4.4|^5.0"
2929
}
3030
}

src/Columns/AbstractColumn.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ public function getSearchCallback()
193193
return $this->internalOptions['search'];
194194
}
195195

196+
public function getAddIfCallback()
197+
{
198+
return $this->internalOptions['addIf'];
199+
}
200+
196201
public function getEmptyData()
197202
{
198203
return $this->internalOptions['emptyData'];
@@ -220,14 +225,18 @@ protected function configureInternalOptions(OptionsResolver $resolver)
220225
'data' => null,
221226
'sort' => null,
222227
'search' => null,
223-
'filter' => array(TextFilter::class, array())
228+
'filter' => array(TextFilter::class, array()),
229+
'addIf' => function() {
230+
return true;
231+
}
224232
));
225233

226234
$resolver->setAllowedTypes('emptyData', ['string']);
227235
$resolver->setAllowedTypes('data', ['Closure', 'null']);
228236
$resolver->setAllowedTypes('sort', ['Closure', 'null']);
229237
$resolver->setAllowedTypes('search', ['Closure', 'null']);
230238
$resolver->setAllowedTypes('filter', ['array', 'null']);
239+
$resolver->setAllowedTypes('addIf', ['Closure']);
231240
}
232241

233242
protected function configureOutputOptions(OptionsResolver $resolver)

src/Columns/ActionColumn.php

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,19 @@ public function buildData($entity)
3636
* @var ActionButton $button
3737
*/
3838
foreach ($this->outputOptions['buttons'] as $key => $button) {
39-
$routeParams = array();
40-
foreach ($button->getRouteParams() as $param) {
41-
$routeParams[$param] = $this->propertyAccessor->getValue($entity, $param);
42-
}
39+
if ($button->getAddIfCallback()()) {
40+
$routeParams = array();
41+
foreach ($button->getRouteParams() as $param) {
42+
$routeParams[$param] = $this->propertyAccessor->getValue($entity, $param);
43+
}
4344

44-
$item[] = array(
45-
'displayName' => $button->getDisplayName(),
46-
'classNames' => $button->getClassNames(),
47-
'route' => $this->router->generate($button->getRouteName(), $routeParams)
48-
);
45+
$item[] = array(
46+
'displayName' => $button->getDisplayName(),
47+
'classNames' => $button->getClassNames(),
48+
'route' => $this->router->generate($button->getRouteName(), $routeParams),
49+
'attr' => $button->formatAttr()
50+
);
51+
}
4952
}
5053

5154
return $item;

src/Columns/ColumnBuilder.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public function remove($dql)
112112
public function buildColumnsArray()
113113
{
114114
$data = array();
115-
foreach ($this->columns as $column) {
115+
foreach ($this->getColumns() as $column) {
116116
$data[] = $column->getOutputOptions();
117117
}
118118

@@ -122,8 +122,19 @@ public function buildColumnsArray()
122122
/**
123123
* @return AbstractColumn[]
124124
*/
125-
public function getColumns()
125+
public function getColumns($ignoreAddIf = false)
126126
{
127+
if (!$ignoreAddIf) {
128+
$columns = array();
129+
foreach ($this->columns as $column) {
130+
if ($column->getAddIfCallback()()) {
131+
$columns[] = $column;
132+
}
133+
}
134+
135+
return $columns;
136+
}
137+
127138
return $this->columns;
128139
}
129140

src/Data/ActionButton.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ public function configureOptions(OptionsResolver $resolver)
4343
'classNames' => '',
4444
'additionalClassNames' => '',
4545
'routeName' => null,
46-
'routeParams' => array('id')
46+
'routeParams' => array('id'),
47+
'attr' => array(),
48+
'addIf' => function () {
49+
return true;
50+
}
4751
));
4852

4953
$resolver->setRequired('displayName');
@@ -54,6 +58,8 @@ public function configureOptions(OptionsResolver $resolver)
5458
$resolver->setAllowedTypes('classNames', 'string');
5559
$resolver->setAllowedTypes('additionalClassNames', 'string');
5660
$resolver->setAllowedTypes('routeParams', 'array');
61+
$resolver->setAllowedTypes('addIf', 'Closure');
62+
$resolver->setAllowedTypes('attr', 'array');
5763
}
5864

5965
public function getClassNames()
@@ -88,4 +94,30 @@ public function getOptions()
8894
return $this->options;
8995
}
9096

97+
public function getAddIfCallback()
98+
{
99+
return $this->options['addIf'];
100+
}
101+
102+
public function getAttr()
103+
{
104+
return $this->options['attr'];
105+
}
106+
107+
public function formatAttr()
108+
{
109+
$formattedAttributes = array();
110+
foreach ($this->options['attr'] as $attribute => $value) {
111+
if (empty($value) === false) {
112+
$formattedAttributes[] = sprintf("%s=\"%s\"", $attribute, $value);
113+
}
114+
}
115+
116+
if (count($formattedAttributes) < 1) {
117+
return "";
118+
}
119+
120+
return " " . implode(" ", $formattedAttributes);
121+
}
122+
91123
}

src/DependencyInjection/HelloBootstrapTableExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function load(array $configs, ContainerBuilder $container)
2727
}
2828

2929
$definition = $container->getDefinition('hello_sebastian_hello_bootstrap_table.hello_bootstrap_table_factory');
30-
$definition->setArgument(3, $config);
30+
$definition->setArgument(4, $config);
3131
}
3232

3333
}

src/HelloBootstrapTable.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Symfony\Component\HttpFoundation\Request;
1414
use Symfony\Component\OptionsResolver\OptionsResolver;
1515
use Symfony\Component\Routing\RouterInterface;
16+
use Symfony\Component\Security\Core\Security;
1617
use Twig\Environment;
1718

1819
abstract class HelloBootstrapTable
@@ -32,6 +33,11 @@ abstract class HelloBootstrapTable
3233
*/
3334
protected $_em;
3435

36+
/**
37+
* @var Security
38+
*/
39+
protected $security;
40+
3541
/**
3642
* @var ColumnBuilder
3743
*/
@@ -74,13 +80,15 @@ abstract class HelloBootstrapTable
7480
* @param RouterInterface $router
7581
* @param EntityManagerInterface $em
7682
* @param Environment $twig
83+
* @param Security $security
7784
* @param array $options
7885
* @param array $defaultOptions
7986
*/
80-
public function __construct(RouterInterface $router, EntityManagerInterface $em, Environment $twig, $options, $defaultOptions = array())
87+
public function __construct(RouterInterface $router, EntityManagerInterface $em, Environment $twig, Security $security, $options, $defaultOptions = array())
8188
{
8289
$this->router = $router;
8390
$this->twig = $twig;
91+
$this->security = $security;
8492
$this->_em = clone $em;
8593
$this->defaultOptions = $defaultOptions;
8694

0 commit comments

Comments
 (0)