-
-
Notifications
You must be signed in to change notification settings - Fork 51
Add callable field #321
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add callable field #321
Changes from 4 commits
7f9689b
f8f212f
dfbe8ea
84925de
432e63d
bfe9951
2f8f6d2
58f0dbc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -319,3 +319,118 @@ $field->setOptions([ | |
// Your options here | ||
]); | ||
``` | ||
|
||
Callable | ||
-------- | ||
|
||
The Callable column aims to offer almost as much flexibility as the Twig column, but without requiring the creation of a template. | ||
You simply need to specify a callable, which allows you to transform the 'data' variable on the fly. | ||
|
||
When defining callables in YAML, only string representations of callables are supported. | ||
When configuring grids using PHP (as opposed to service grid configuration), both string and array callables are supported. However, closures cannot be used due to restrictions in Symfony's configuration (values of type "Closure" are not permitted in service configuration files). | ||
By contrast, when configuring grids with service definitions, you can use both callables and closures. | ||
|
||
Here are some examples of what you can do: | ||
|
||
<details open><summary>Yaml</summary> | ||
|
||
```yaml | ||
# config/packages/sylius_grid.yaml | ||
|
||
sylius_grid: | ||
grids: | ||
app_user: | ||
fields: | ||
id: | ||
type: callable | ||
options: | ||
callable: "callable:App\\Helper\\GridHelper::addHashPrefix" | ||
label: app.ui.id | ||
name: | ||
type: callable | ||
options: | ||
callable: "callable:strtoupper" | ||
label: app.ui.name | ||
``` | ||
|
||
</details> | ||
|
||
<details open><summary>PHP</summary> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To match existing documentation, please add YAML example as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not include documentation for the YAML format because I believe it's impossible to define a callback field in this format. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feature is not complete then and cannot be merged until YAML support will be dropped. Here is example on how callback can be implemented with non-php config format. https://symfony.com/doc/current/reference/constraints/Callback.html#external-callbacks-and-closures There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can do it. The repository can be a callback in YAML. app_book_by_english_authors:
driver:
name: doctrine/orm
options:
class: App\Entity\Book
repository:
method: [expr:service('app.english_books_query_builder'), create] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I reworked the feature and introduced a new way to define callbacks, inspired by Loic's comment: sylius_grid:
grids:
app_user:
fields:
name:
type: callback
options:
callback: "callback:strtoupper"
label: app.ui.name This approach allows string callables to be defined directly in YAML. I’ve documented this change here: SyliusGridBundle PR #321. To implement this, I copied the Since the resource bundle is not a required dependencie, I think this is fine to copy the class. However having two |
||
|
||
```php | ||
<?php | ||
// config/packages/sylius_grid.php | ||
|
||
use Sylius\Bundle\GridBundle\Builder\Field\CallableField; | ||
use Sylius\Bundle\GridBundle\Builder\GridBuilder; | ||
use Sylius\Bundle\GridBundle\Config\GridConfig; | ||
|
||
return static function (GridConfig $grid): void { | ||
$grid->addGrid(GridBuilder::create('app_user', '%app.model.user.class%') | ||
->addField( | ||
CallableField::create('id', 'App\\Helper\\GridHelper::addHashPrefix') | ||
->setLabel('app.ui.id') | ||
) | ||
// or | ||
->addField( | ||
CallableField::create('id', ['App\\Helper\\GridHelper', 'addHashPrefix']) | ||
->setLabel('app.ui.id') | ||
) | ||
|
||
->addField( | ||
CallableField::create('name', 'strtoupper') | ||
->setLabel('app.ui.name') | ||
) | ||
) | ||
}; | ||
``` | ||
|
||
OR | ||
|
||
```php | ||
<?php | ||
# src/Grid/UserGrid.php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace App\Grid; | ||
|
||
use App\Entity\User; | ||
use Sylius\Bundle\GridBundle\Builder\Field\CallableField; | ||
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface; | ||
use Sylius\Bundle\GridBundle\Grid\AbstractGrid; | ||
use Sylius\Bundle\GridBundle\Grid\ResourceAwareGridInterface; | ||
|
||
final class UserGrid extends AbstractGrid implements ResourceAwareGridInterface | ||
{ | ||
public static function getName(): string | ||
{ | ||
return 'app_user'; | ||
} | ||
|
||
public function buildGrid(GridBuilderInterface $gridBuilder): void | ||
{ | ||
$gridBuilder | ||
->addField( | ||
CallableField::create('id', GridHelper::addHashPrefix(...)) | ||
->setLabel('app.ui.id') | ||
) | ||
->addField( | ||
CallableField::create('name', 'strtoupper') | ||
->setLabel('app.ui.name') | ||
) | ||
->addField( | ||
CallableField::create('roles' fn (array $roles): string => implode(', ', $roles)) | ||
->setLabel('app.ui.roles') | ||
) | ||
; | ||
} | ||
|
||
public function getResourceClass(): string | ||
{ | ||
return User::class; | ||
} | ||
} | ||
``` | ||
|
||
</details> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
parameters: | ||
ignoreErrors: | ||
- | ||
message: "#^Dead catch \\- Throwable is never thrown in the try block\\.$#" | ||
count: 1 | ||
path: src/Component/FieldTypes/CallableFieldType.php |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Sylius package. | ||
* | ||
* (c) Sylius Sp. z o.o. | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sylius\Bundle\GridBundle\Builder\Field; | ||
|
||
final class CallableField | ||
{ | ||
public static function create(string $name, callable $callable, bool $htmlspecialchars = true): FieldInterface | ||
{ | ||
return Field::create($name, 'callable') | ||
->setOption('callable', $callable) | ||
->setOption('htmlspecialchars', $htmlspecialchars) | ||
; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Sylius package. | ||
* | ||
* (c) Sylius Sp. z o.o. | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sylius\Bundle\GridBundle\Parser; | ||
|
||
final class OptionsParser implements OptionsParserInterface | ||
{ | ||
public function parseOptions(array $parameters): array | ||
{ | ||
return array_map( | ||
/** | ||
* @param mixed $parameter | ||
* | ||
* @return mixed | ||
*/ | ||
function ($parameter) { | ||
loic425 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (is_array($parameter)) { | ||
return $this->parseOptions($parameter); | ||
} | ||
|
||
return $this->parseOption($parameter); | ||
}, | ||
$parameters, | ||
); | ||
} | ||
|
||
/** | ||
* @param mixed $parameter | ||
* | ||
* @return mixed | ||
*/ | ||
private function parseOption($parameter) | ||
loic425 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if (!is_string($parameter)) { | ||
return $parameter; | ||
} | ||
|
||
if (0 === strpos($parameter, 'callable:')) { | ||
loic425 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return $this->parseOptionCallable(substr($parameter, 9)); | ||
} | ||
|
||
return $parameter; | ||
} | ||
|
||
private function parseOptionCallable(string $callable): \Closure | ||
{ | ||
if (!is_callable($callable)) { | ||
throw new \RuntimeException(\sprintf('%s is not a callable.', $callable)); | ||
diimpp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
return $callable(...); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Sylius package. | ||
* | ||
* (c) Sylius Sp. z o.o. | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Sylius\Bundle\GridBundle\Parser; | ||
|
||
interface OptionsParserInterface | ||
{ | ||
public function parseOptions(array $parameters): array; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.