This commit is contained in:
mamazu 2026-07-03 15:08:12 +00:00 committed by GitHub
commit e1fb90a2a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
89 changed files with 5021 additions and 25 deletions

1
.env
View file

@ -46,3 +46,4 @@ MAILER_DSN=null://null
###< symfony/mailer ### ###< symfony/mailer ###
SYLIUS_PAYMENT_ENCRYPTION_KEY_PATH=%kernel.project_dir%/config/encryption/dev.key SYLIUS_PAYMENT_ENCRYPTION_KEY_PATH=%kernel.project_dir%/config/encryption/dev.key
TEST_SYLIUS_USE_LEGACY_GRID_CONFIG=0

View file

@ -44,7 +44,7 @@ jobs:
phpunit-cli-api: phpunit-cli-api:
needs: get-matrix needs: get-matrix
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: "PHPUnit, CLI, API, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MariaDB ${{ matrix.mariadb }}, State Machine Adapter ${{ matrix.state_machine_adapter }}${{ matrix.doctrine_bundle && format(', DoctrineBundle {0}', matrix.doctrine_bundle) || '' }}${{ matrix.api_platform && format(', ApiPlatform {0}', matrix.api_platform) || '' }}" name: "PHPUnit, CLI, API, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MariaDB ${{ matrix.mariadb }}, State Machine Adapter ${{ matrix.state_machine_adapter }}${{ matrix.doctrine_bundle && format(', DoctrineBundle {0}', matrix.doctrine_bundle) || '' }}${{ matrix.api_platform && format(', ApiPlatform {0}', matrix.api_platform) || '' }}${{ matrix.legacy_grid_config && format(', LegacyGridConfig {0}', matrix.legacy_grid_config) || '' }}"
timeout-minutes: 20 timeout-minutes: 20
strategy: strategy:
fail-fast: false fail-fast: false
@ -53,6 +53,7 @@ jobs:
env: env:
APP_ENV: test_cached APP_ENV: test_cached
TEST_SYLIUS_STATE_MACHINE_ADAPTER: "${{ matrix.state_machine_adapter }}" TEST_SYLIUS_STATE_MACHINE_ADAPTER: "${{ matrix.state_machine_adapter }}"
TEST_SYLIUS_USE_LEGACY_GRID_CONFIG: ${{ matrix.legacy_grid_config || true }}
BEHAT_BASE_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f progress" BEHAT_BASE_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f progress"
BEHAT_RERUN_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f pretty --rerun" BEHAT_RERUN_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f pretty --rerun"
@ -153,7 +154,7 @@ jobs:
behat-ui: behat-ui:
needs: get-matrix needs: get-matrix
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: "UI, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MariaDB ${{ matrix.mariadb }}, State Machine Adapter ${{ matrix.state_machine_adapter }}${{ matrix.doctrine_bundle && format(', DoctrineBundle {0}', matrix.doctrine_bundle) || '' }}${{ matrix.api_platform && format(', ApiPlatform {0}', matrix.api_platform) || '' }}" name: "UI, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MariaDB ${{ matrix.mariadb }}, State Machine Adapter ${{ matrix.state_machine_adapter }}${{ matrix.doctrine_bundle && format(', DoctrineBundle {0}', matrix.doctrine_bundle) || '' }}${{ matrix.api_platform && format(', ApiPlatform {0}', matrix.api_platform) || '' }}${{ matrix.legacy_grid_config && format(', LegacyGridConfig {0}', matrix.legacy_grid_config) || '' }}"
timeout-minutes: 20 timeout-minutes: 20
strategy: strategy:
fail-fast: false fail-fast: false
@ -162,6 +163,7 @@ jobs:
env: env:
APP_ENV: test_cached APP_ENV: test_cached
TEST_SYLIUS_STATE_MACHINE_ADAPTER: "${{ matrix.state_machine_adapter }}" TEST_SYLIUS_STATE_MACHINE_ADAPTER: "${{ matrix.state_machine_adapter }}"
TEST_SYLIUS_USE_LEGACY_GRID_CONFIG: ${{ matrix.legacy_grid_config || true }}
BEHAT_BASE_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f progress" BEHAT_BASE_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f progress"
BEHAT_RERUN_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f pretty --rerun" BEHAT_RERUN_CMD: "vendor/bin/behat --colors --strict --no-interaction -vvv -f pretty --rerun"

View file

@ -23,14 +23,16 @@
"symfony": "~6.4.0", "symfony": "~6.4.0",
"mariadb": "10.11.13", "mariadb": "10.11.13",
"doctrine_bundle": "^2.0", "doctrine_bundle": "^2.0",
"state_machine_adapter": "winzou_state_machine" "state_machine_adapter": "winzou_state_machine",
"legacy_grid_config": true
}, },
{ {
"php": "8.5", "php": "8.5",
"symfony": "~7.4.0", "symfony": "~7.4.0",
"mariadb": "11.4.7", "mariadb": "11.4.7",
"doctrine_bundle": "^3.0", "doctrine_bundle": "^3.0",
"state_machine_adapter": "symfony_workflow" "state_machine_adapter": "symfony_workflow",
"legacy_grid_config": false
} }
] ]
}, },
@ -166,13 +168,17 @@
"state_machine_adapter": [ "state_machine_adapter": [
"symfony_workflow" "symfony_workflow"
], ],
"legacy_grid_config": [
false
],
"include": [ "include": [
{ {
"php": "8.3", "php": "8.3",
"symfony": "~7.4.0", "symfony": "~7.4.0",
"mariadb": "11.4.7", "mariadb": "11.4.7",
"doctrine_bundle": "^2.0", "doctrine_bundle": "^2.0",
"state_machine_adapter": "winzou_state_machine" "state_machine_adapter": "winzou_state_machine",
"legacy_grid_config": true
} }
] ]
}, },

View file

@ -71,6 +71,62 @@
> and their default parameters include Payment Request-specific values (e.g. `hash: paymentRequest.getHash()`). > and their default parameters include Payment Request-specific values (e.g. `hash: paymentRequest.getHash()`).
> Do not use them to configure the Payum after-pay redirect. > Do not use them to configure the Payum after-pay redirect.
### Grid providers are now configurable
As part of the ongoing modernization of the Grid component, Sylius now provides grid definitions in both **YAML** and **PHP**.
Moving grid configuration to PHP provides several benefits:
* Better IDE support, including autocompletion and static analysis.
* Improved maintainability for complex grid definitions.
PHP grid definitions are the recommended approach going forward and represent the direction of Sylius 3.0. To support a
smooth migration, Sylius continues to support legacy YAML-based grids and now allows you to choose which format is used
for each grid.
### Migration strategy
During the migration period, grid definitions can be loaded from either:
* **YAML** (legacy format)
* **PHP** (recommended format)
You can configure the format globally:
```yaml
sylius_core:
grid:
use_legacy_config: true # Use YAML grid definitions globally (default: false)
```
Or override the format for individual grids:
```yaml
sylius_core:
grid:
grids:
sylius_admin_product_variant:
use_legacy_config: false # Use PHP configuration for this grid
```
This makes it possible to migrate grids incrementally rather than converting your entire application at once.
> **Important**
>
> A grid can only be loaded from a single source. YAML and PHP definitions for the same grid cannot be merged. When migrating a grid to PHP, you must recreate the complete grid definition in PHP, including any vendor configuration you want to preserve.
### Migration tooling
To simplify the conversion process, you can use the community-maintained Grid configuration converter:
* [Grid Config Converter](https://github.com/mamazu/grid-config-converter?utm_source=chatgpt.com)
The converter can help bootstrap the migration from YAML to PHP and reduce the amount of manual work required.
### Learn more
For a complete overview of the Grid component, see the [Grid documentation](https://stack.sylius.com/grid/index).
## Dependencies ## Dependencies
1. The `behat/transliterator` package has been **deprecated** and will be removed in Sylius 3.0. 1. The `behat/transliterator` package has been **deprecated** and will be removed in Sylius 3.0.

View file

@ -74,8 +74,8 @@
"sylius-labs/association-hydrator": "^1.2", "sylius-labs/association-hydrator": "^1.2",
"sylius-labs/doctrine-migrations-extra-bundle": "^0.2 || ^0.3", "sylius-labs/doctrine-migrations-extra-bundle": "^0.2 || ^0.3",
"sylius/fixtures-bundle": "^1.9", "sylius/fixtures-bundle": "^1.9",
"sylius/grid": "^1.13", "sylius/grid": "^1.14",
"sylius/grid-bundle": "^1.13", "sylius/grid-bundle": "^1.16@alpha",
"sylius/mailer": "^2.1", "sylius/mailer": "^2.1",
"sylius/mailer-bundle": "^2.1", "sylius/mailer-bundle": "^2.1",
"sylius/registry": "^1.6", "sylius/registry": "^1.6",

View file

@ -8,6 +8,8 @@ imports:
parameters: parameters:
sylius_core.public_dir: '%kernel.project_dir%/public' sylius_core.public_dir: '%kernel.project_dir%/public'
sylius_core.grids_configuration:
use_legacy_config: '%env(bool:TEST_SYLIUS_USE_LEGACY_GRID_CONFIG)%'
sylius_api: sylius_api:
enabled: true enabled: true

View file

@ -5,10 +5,12 @@ declare(strict_types=1);
use Arkitect\ClassSet; use Arkitect\ClassSet;
use Arkitect\CLI\Config; use Arkitect\CLI\Config;
use Arkitect\Expression\ForClasses\HaveNameMatching; use Arkitect\Expression\ForClasses\HaveNameMatching;
use Arkitect\Expression\ForClasses\Implement;
use Arkitect\Expression\ForClasses\IsFinal; use Arkitect\Expression\ForClasses\IsFinal;
use Arkitect\Expression\ForClasses\NotDependsOnTheseNamespaces; use Arkitect\Expression\ForClasses\NotDependsOnTheseNamespaces;
use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces; use Arkitect\Expression\ForClasses\ResideInOneOfTheseNamespaces;
use Arkitect\Rules\Rule; use Arkitect\Rules\Rule;
use Sylius\Bundle\GridBundle\Grid\GridInterface;
return static function (Config $config): void return static function (Config $config): void
{ {
@ -23,6 +25,15 @@ return static function (Config $config): void
, ,
); );
$config->add(
$testsClassSet,
Rule::allClasses()
->that(new Implement(GridInterface::class))
->should(new IsFinal())
->because('Grids should only be decorated')
,
);
$separationClassSet = ClassSet::fromDir(__DIR__ . '/src/Sylius/{Component,Bundle}'); $separationClassSet = ClassSet::fromDir(__DIR__ . '/src/Sylius/{Component,Bundle}');
$config->add( $config->add(
@ -86,5 +97,10 @@ return static function (Config $config): void
)) ))
->because('Api should not depend on Admin and Shop') ->because('Api should not depend on Admin and Shop')
, ,
Rule::allClasses()
->that(new Implement(GridInterface::class))
->should(new IsFinal())
->because('Grids should only be decorated')
,
); );
}; };

View file

@ -0,0 +1,86 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\BooleanFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.admin_user.class%', name: self::NAME)]
final class AdminUserGrid implements AdminUserGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->addOrderBy('createdAt', 'desc')
->setLimits([10, 25, 50])
->withFields(
TwigField::create('email', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.email')
->setSortable(true),
StringField::create('firstName')
->setLabel('sylius.ui.first_name')
->setSortable(true),
StringField::create('lastName')
->setLabel('sylius.ui.last_name')
->setSortable(true),
StringField::create('username')
->setLabel('sylius.ui.username')
->setSortable(true),
TwigField::create('createdAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.registration_date')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
)
->withFilters(
StringFilter::create(
name: 'search',
fields: ['email', 'username', 'firstName', 'lastName'],
)
->setLabel('sylius.ui.search'),
BooleanFilter::create('enabled')
->setLabel('sylius.ui.enabled'),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface AdminUserGridInterface
{
public const NAME = 'sylius_admin_admin_user';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,164 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\ShowAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\BooleanFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\DateFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\EntityFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
use Sylius\Component\Promotion\Model\CatalogPromotionStates;
#[AsGrid(resourceClass: '%sylius.model.catalog_promotion.class%', name: self::NAME)]
final class CatalogPromotionGrid implements CatalogPromotionGridInterface
{
public function __construct(
private readonly string $channelClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('code', 'asc')
->withFields(
TwigField::create('priority', '@SyliusAdmin/catalog_promotion/grid/field/priority.html.twig')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
])
->setLabel('sylius.ui.priority')
->setSortable(true),
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setSortable(true),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
TwigField::create('channels', '@SyliusAdmin/shared/grid/field/channels.html.twig')
->setLabel('sylius.ui.channels')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('startDate', '@SyliusAdmin/catalog_promotion/grid/field/date.html.twig')
->setLabel('sylius.ui.start_date')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'text-center',
],
]),
TwigField::create('endDate', '@SyliusAdmin/catalog_promotion/grid/field/date.html.twig')
->setLabel('sylius.ui.end_date')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'text-center',
],
]),
TwigField::create('state', '@SyliusAdmin/catalog_promotion/grid/field/state.html.twig')
->setLabel('sylius.ui.state')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
)
->withFilters(
StringFilter::create(
'search',
fields: ['name', 'code'],
type: 'contains',
)
->setLabel('sylius.ui.search'),
EntityFilter::create(
'channel',
resourceClass: $this->channelClass,
fields: ['channels.id'],
)
->setLabel('sylius.ui.channel'),
DateFilter::create('startDate')
->setLabel('sylius.ui.start_date')
->setOptions([
'inclusive_to' => true,
]),
DateFilter::create('endDate')
->setLabel('sylius.ui.end_date')
->setOptions([
'inclusive_to' => true,
]),
BooleanFilter::create('enabled')
->setLabel('sylius.ui.enabled'),
Filter::create('state', 'select')
->setLabel('sylius.ui.state')
->addFormOption('choices', [
'sylius.ui.active' => CatalogPromotionStates::STATE_ACTIVE,
'sylius.ui.inactive' => CatalogPromotionStates::STATE_INACTIVE,
]),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
ShowAction::create(),
Action::create('show_variants', 'show')
->setLabel('sylius.ui.list_variants')
->setIcon('tabler:list-letters')
->setOptions([
'link' => [
'route' => 'sylius_admin_catalog_promotion_product_variant_index',
'parameters' => [
'id' => 'resource.id',
],
],
]),
UpdateAction::create(),
Action::create('delete', 'delete_catalog_promotion')
->setOptions([
'link' => [
'route' => 'sylius_admin_catalog_promotion_delete',
'parameters' => [
'code' => 'resource.code',
],
],
'state' => 'resource.state',
]),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface CatalogPromotionGridInterface
{
public const NAME = 'sylius_admin_catalog_promotion';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,71 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\BooleanFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.channel.class%', name: self::NAME)]
final class ChannelGrid implements ChannelGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('nameAndDescription', 'asc')
->withFields(
TwigField::create('nameAndDescription', '@SyliusAdmin/shared/grid/field/channel.html.twig')
->setLabel('sylius.ui.name')
->setPath('.')
->setSortable(true, 'name'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true, 'code'),
TwigField::create('themeName', '@SyliusAdmin/channel/grid/field/theme.html.twig')
->setLabel('sylius.ui.theme')
->setSortable(true),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
)
->withFilters(
StringFilter::create('search', ['code', 'name'])
->setLabel('sylius.ui.search'),
BooleanFilter::create('enabled')
->setLabel('sylius.ui.enabled'),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ChannelGridInterface
{
public const NAME = 'sylius_admin_channel';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,50 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Field\DateTimeField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\DateFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.channel_pricing_log_entry.class%', name: self::NAME)]
final class ChannelPricingLogEntryGrid implements ChannelPricingLogEntryGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createByChannelPricingIdListQueryBuilder', [
'$channelPricingId',
])
->setLimits([10, 25, 50])
->withFields(
TwigField::create('price', '@SyliusAdmin/channel_pricing_log_entry/grid/field/price.html.twig')
->setLabel('sylius.ui.price')
->setPath('.'),
TwigField::create('originalPrice', '@SyliusAdmin/channel_pricing_log_entry/grid/field/original_price.html.twig')
->setLabel('sylius.ui.original_price')
->setPath('.'),
DateTimeField::create('loggedAt')
->setLabel('sylius.ui.logged_at'),
)
->withFilters(
DateFilter::create('loggedAt')
->setLabel('sylius.ui.logged_at'),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ChannelPricingLogEntryGridInterface
{
public const NAME = 'sylius_admin_channel_pricing_log_entry';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,64 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.country.class%', name: self::NAME)]
final class CountryGrid implements CountryGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('code', 'asc')
->withFields(
TwigField::create('name', '@SyliusAdmin/country/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setPath('.')
->setSortable(true, 'code'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
)
->withFilters(
Filter::create('code', 'string')
->setLabel('sylius.ui.code'),
Filter::create('enabled', 'boolean')
->setLabel('sylius.ui.enabled'),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface CountryGridInterface
{
public const NAME = 'sylius_admin_country';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,52 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.currency.class%', name: self::NAME)]
final class CurrencyGrid implements CurrencyGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('code', 'asc')
->withFields(
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
StringField::create('name')
->setLabel('sylius.ui.name'),
)
->withFilters(
StringFilter::create('code')
->setLabel('sylius.ui.code'),
)
->withMainActions(
CreateAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface CurrencyGridInterface
{
public const NAME = 'sylius_admin_currency';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,108 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\ShowAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.customer.class%', name: self::NAME)]
final class CustomerGrid implements CustomerGridInterface
{
public function __construct(
private readonly string $customerGroupClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('createdAt', 'desc')
->withFields(
TwigField::create('email', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.email')
->setSortable(true),
StringField::create('lastName')
->setLabel('sylius.ui.last_name')
->setSortable(true),
StringField::create('firstName')
->setLabel('sylius.ui.first_name')
->setSortable(true),
TwigField::create('createdAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.registration_date')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('enabled', '@SyliusAdmin/customer/grid/field/enabled.html.twig')
->setLabel('sylius.ui.enabled')
->setPath('.')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('verified', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.verified')
->setPath('user?.verified')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
)
->withFilters(
StringFilter::create('search', ['email', 'firstName', 'lastName'])
->setLabel('sylius.ui.search'),
Filter::create('group', 'ux_autocomplete')
->setLabel('sylius.ui.customer_groups')
->setFormOptions([
'multiple' => true,
'extra_options' => [
'class' => $this->customerGroupClass,
'choice_label' => 'name',
],
])
->setOptions([
'fields' => ['group.id'],
]),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
Action::create('show_orders', 'show')
->setLabel('sylius.ui.show_orders')
->setIcon('tabler:shopping-bag')
->setOptions([
'link' => [
'route' => 'sylius_admin_customer_order_index',
'parameters' => ['id' => 'resource.id'],
],
]),
ShowAction::create(),
UpdateAction::create(),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface CustomerGridInterface
{
public const NAME = 'sylius_admin_customer';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,66 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.customer_group.class%', name: self::NAME)]
final class CustomerGroupGrid implements CustomerGroupGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->addOrderBy('name', 'asc')
->setLimits([10, 25, 50])
->withFields(
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-75',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-25',
],
]),
)
->withFilters(
StringFilter::create('search', ['code', 'name'])
->setLabel('sylius.ui.search'),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface CustomerGroupGridInterface
{
public const NAME = 'sylius_admin_customer_group';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,42 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.order.class%', name: self::NAME)]
final class CustomerOrderGrid implements CustomerOrderGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createByCustomerIdCriteriaAwareQueryBuilder', [
'criteria' => null,
'customerId' => '$id',
])
->extends('sylius_admin_order')
->addOrderBy('number', 'desc')
->withFields(
StringField::create('customer')
->setEnabled(false),
)
->withFilters(
Filter::create('customer', 'string')
->setEnabled(false),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface CustomerOrderGridInterface
{
public const NAME = 'sylius_admin_customer_order';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,72 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Filter\EntityFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.exchange_rate.class%', name: self::NAME)]
final class ExchangeRateGrid implements ExchangeRateGridInterface
{
public function __construct(
private readonly string $currencyClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('id', 'desc')
->withFields(
StringField::create('id')
->setEnabled(false)
->setSortable(true),
StringField::create('sourceCurrency')
->setLabel('sylius.ui.source_currency')
->setPath('sourceCurrency.name'),
StringField::create('targetCurrency')
->setLabel('sylius.ui.target_currency')
->setPath('targetCurrency.name'),
StringField::create('ratio')
->setLabel('sylius.ui.ratio')
->setPath('ratio')
->setSortable(true),
)
->withFilters(
EntityFilter::create('currency', $this->currencyClass, fields: ['sourceCurrency', 'targetCurrency'])
->setLabel('sylius.ui.currency')
->addFormOption('choice_label', 'name'),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ExchangeRateGridInterface
{
public const NAME = 'sylius_admin_exchange_rate';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,107 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_variant.class%', name: self::NAME)]
final class InventoryGrid implements InventoryGridInterface
{
public function __construct(
private readonly string $productClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('name', 'asc')
->setRepositoryMethod('createInventoryListQueryBuilder', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
])
->withFields(
TwigField::create('name', '@SyliusAdmin/inventory/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setPath('.')
->setSortable(true, 'product.translations.name')
->withOptions([
'vars' => [
'th_class' => 'w-75',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-25',
],
]),
TwigField::create('inventory', '@SyliusAdmin/inventory/grid/field/inventory.html.twig')
->setLabel('sylius.ui.inventory')
->setPath('.'),
)
->withFilters(
Filter::create('code', 'string')
->setLabel('sylius.ui.code'),
Filter::create('name', 'string')
->setLabel('sylius.ui.name')
->setOptions([
'fields' => [
'translation.name',
],
]),
Filter::create('product', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.product')
->setFormOptions([
'multiple' => false,
'extra_options' => [
'class' => $this->productClass,
'translation_fields' => ['name'],
'choice_label' => 'name',
],
])
->setOptions([
'fields' => ['product.id'],
]),
)
->withItemActions(
Action::create('update_product', 'update')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_update',
'parameters' => [
'id' => 'resource.product.id',
],
],
])
->setLabel('sylius.ui.edit_product'),
UpdateAction::create([
'link' => [
'parameters' => [
'id' => 'resource.id',
'productId' => 'resource.product.id',
],
],
]),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface InventoryGridInterface
{
public const NAME = 'sylius_admin_inventory';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,50 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.locale.class%', name: self::NAME)]
final class LocaleGrid implements LocaleGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('code', 'asc')
->withFields(
TwigField::create('name', '@SyliusAdmin/locale/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setPath('.'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
)
->withFilters(
Filter::create('code', 'string')
->setLabel('sylius.ui.code'),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
DeleteAction::create(),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface LocaleGridInterface
{
public const NAME = 'sylius_admin_locale';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,178 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\ShowAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\SelectFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.order.class%', name: self::NAME)]
final class OrderGrid implements OrderGridInterface
{
public function __construct(
private readonly string $channelClass,
private readonly string $customerClass,
private readonly string $productClass,
private readonly string $productVariantClass,
private readonly string $shippingMethodClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->setRepositoryMethod(
'createCriteriaAwareSearchListQueryBuilder',
['criteria' => '$criteria'],
)
->addOrderBy('number', 'desc')
->withFields(
TwigField::create('number', '@SyliusAdmin/shared/grid/field/order_number.html.twig')
->setLabel('sylius.ui.number')
->setPath('.')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1',
],
]),
TwigField::create('date', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.date')
->setPath('checkoutCompletedAt')
->setSortable(true, 'checkoutCompletedAt')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('customer', '@SyliusAdmin/shared/grid/field/customer.html.twig')
->setLabel('sylius.ui.customer')
->setSortable(true, 'customer.lastName')
->withOptions([
'vars' => [
'th_class' => 'w-100',
],
]),
TwigField::create('channel', '@SyliusAdmin/shared/grid/field/channel.html.twig')
->setLabel('sylius.ui.channel')
->setSortable(true, 'channel.code'),
TwigField::create('state', '@SyliusAdmin/order/grid/field/order_state.html.twig')
->setLabel('sylius.ui.state')
->setSortable(true),
TwigField::create('paymentState', '@SyliusAdmin/order/grid/field/payment_state.html.twig')
->setLabel('sylius.ui.payment_state')
->setSortable(true),
TwigField::create('shippingState', '@SyliusAdmin/order/grid/field/shipping_state.html.twig')
->setLabel('sylius.ui.shipping_state')
->setSortable(true),
TwigField::create('total', '@SyliusAdmin/order/grid/field/order_total.html.twig')
->setLabel('sylius.ui.total')
->setPath('.')
->setSortable(true, 'total')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-end',
'td_class' => 'text-end',
],
]),
StringField::create('currencyCode')
->setLabel('sylius.ui.currency')
->setSortable(true),
)
->withFilters(
SelectFilter::create('state', [
'sylius.ui.cancelled' => 'cancelled',
'sylius.ui.new' => 'new',
'sylius.ui.fulfilled' => 'fulfilled',
])
->setLabel('sylius.ui.state'),
Filter::create('product', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.product')
->setFormOptions([
'multiple' => true,
'extra_options' => [
'class' => $this->productClass,
'translation_fields' => ['name'],
'choice_label' => 'name',
],
]),
Filter::create('variant', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.variant')
->setFormOptions([
'multiple' => true,
'extra_options' => [
'class' => $this->productVariantClass,
'translation_fields' => ['name'],
'choice_label' => 'descriptor',
],
]),
Filter::create('number', 'string')
->setLabel('sylius.ui.number')
->setFormOptions([
'type' => StringFilter::TYPE_CONTAINS,
]),
Filter::create('customer', 'ux_autocomplete')
->setLabel('sylius.ui.customer')
->setFormOptions([
'extra_options' => [
'class' => $this->customerClass,
'choice_label' => 'fullname',
],
]),
Filter::create('date', 'date')
->setLabel('sylius.ui.date')
->setOptions([
'field' => 'checkoutCompletedAt',
'inclusive_to' => true,
]),
Filter::create('channel', 'ux_autocomplete')
->setLabel('sylius.ui.channel')
->setFormOptions([
'extra_options' => [
'class' => $this->channelClass,
'choice_label' => 'name',
],
]),
Filter::create('total', 'money')
->setLabel('sylius.ui.total')
->setOptions([
'currency_field' => 'currencyCode',
]),
Filter::create('shipping_method', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.shipping_method')
->setOptions([
'fields' => [
'shipments.method.id',
],
])
->setFormOptions([
'extra_options' => [
'class' => $this->shippingMethodClass,
'translation_fields' => ['name'],
'choice_label' => 'name',
],
]),
)
->withItemActions(
ShowAction::create(),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface OrderGridInterface
{
public const NAME = 'sylius_admin_order';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,125 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.payment.class%', name: self::NAME)]
final class PaymentGrid implements PaymentGridInterface
{
public function __construct(
private readonly string $channelClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createListQueryBuilder')
->addOrderBy('createdAt', 'desc')
->setLimits([10, 25, 50])
->withFields(
TwigField::create('createdAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.date')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('number', '@SyliusAdmin/shared/grid/field/order_number.html.twig')
->setLabel('sylius.ui.order')
->setPath('order')
->withOptions([
'vars' => [
'th_class' => 'w-1',
],
]),
TwigField::create('customer', '@SyliusAdmin/shared/grid/field/customer.html.twig')
->setLabel('sylius.ui.customer')
->setPath('order.customer')
->withOptions([
'vars' => [
'th_class' => 'w-100',
],
]),
TwigField::create('channel', '@SyliusAdmin/shared/grid/field/channel.html.twig')
->setLabel('sylius.ui.channel')
->setPath('order.channel'),
TwigField::create('state', '@SyliusAdmin/shared/grid/field/payment_state.html.twig')
->setLabel('sylius.ui.state')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
)
->withFilters(
Filter::create('state', 'select')
->setLabel('sylius.ui.state')
->setFormOptions([
'choices' => [
'sylius.ui.cancelled' => 'cancelled',
'sylius.ui.completed' => 'completed',
'sylius.ui.failed' => 'failed',
'sylius.ui.new' => 'new',
'sylius.ui.processing' => 'processing',
'sylius.ui.refunded' => 'refunded',
],
]),
Filter::create('channel', 'entity')
->setLabel('sylius.ui.channel')
->setOptions([
'fields' => [
'order.channel',
],
])
->setFormOptions([
'class' => $this->channelClass,
]),
)
->withItemActions(
Action::create('list_payment_requests', 'show')
->setIcon('tabler:list-letters')
->setLabel('sylius.ui.list_payment_requests')
->setOptions([
'link' => [
'route' => 'sylius_admin_payment_request_index',
'parameters' => [
'paymentId' => 'resource.id',
],
],
]),
Action::create('complete', 'apply_transition')
->setLabel('sylius.ui.complete')
->setIcon('tabler:credit-card-pay')
->setOptions([
'link' => [
'route' => 'sylius_admin_payment_complete',
'parameters' => [
'id' => 'resource.id',
],
],
'class' => 'teal',
'transition' => 'complete',
'graph' => 'sylius_payment',
]),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface PaymentGridInterface
{
public const NAME = 'sylius_admin_payment';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,87 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.payment_method.class%', name: self::NAME)]
final class PaymentMethodGrid implements PaymentMethodGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createListQueryBuilder', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
])
->addOrderBy('position', 'asc')
->setLimits([10, 25, 50])
->withFields(
TwigField::create('position', '@SyliusUi/grid/field/position.html.twig')
->setLabel('sylius.ui.position')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setSortable(true, 'translation.name'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true, 'code'),
TwigField::create('gateway', '@SyliusUi/grid/field/humanized.html.twig')
->setLabel('sylius.ui.gateway')
->setPath('gatewayConfig.factoryName')
->setSortable(true, 'gatewayConfig.factoryName'),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
)
->withFilters(
StringFilter::create('search', ['code', 'translation.name'])
->setLabel('sylius.ui.search')
->setFormOptions(['type' => StringFilter::TYPE_CONTAINS]),
Filter::create('enabled', 'boolean')
->setLabel('sylius.ui.enabled'),
)
->withMainActions(
Action::create('create', 'create_payment_method'),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface PaymentMethodGridInterface
{
public const NAME = 'sylius_admin_payment_method';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,116 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\ShowAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\SelectFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
use Sylius\Component\Payment\Model\PaymentRequestInterface;
#[AsGrid(resourceClass: '%sylius.model.payment_request.class%', name: self::NAME)]
final class PaymentRequestGrid implements PaymentRequestGridInterface
{
public function __construct(
private readonly string $paymentMethodClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder->setRepositoryMethod('createQueryBuilderForPayment', [
'paymentId' => '$paymentId',
]);
$gridBuilder->setLimits([10, 25, 50]);
$gridBuilder->addOrderBy('createdAt', 'desc');
$gridBuilder
->withFields(
StringField::create('hash')
->setLabel('sylius.ui.hash')
->setSortable(true),
TwigField::create('method', '@SyliusAdmin/payment_request/grid/field/method.html.twig')
->setLabel('sylius.ui.payment_method')
->setPath('.'),
TwigField::create('action', '@SyliusAdmin/payment_request/grid/field/action.html.twig')
->setLabel('sylius.ui.action'),
TwigField::create('state', '@SyliusAdmin/payment_request/grid/field/state.html.twig')
->setLabel('sylius.ui.state'),
TwigField::create('createdAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.creation_date')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('updatedAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.updating_date')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
)
->withFilters(
Filter::create('payment_method', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.payment_method')
->setFormOptions(['extra_options' => [
'class' => $this->paymentMethodClass,
'translation_fields' => ['name'],
'choice_label' => 'name',
]])
->setOptions([
'fields' => ['method.id'],
]),
SelectFilter::create('action', [
'sylius.ui.authorize' => PaymentRequestInterface::ACTION_AUTHORIZE,
'sylius.ui.cancel' => PaymentRequestInterface::ACTION_CANCEL,
'sylius.ui.capture' => PaymentRequestInterface::ACTION_CAPTURE,
'sylius.ui.notify' => PaymentRequestInterface::ACTION_NOTIFY,
'sylius.ui.payout' => PaymentRequestInterface::ACTION_PAYOUT,
'sylius.ui.refund' => PaymentRequestInterface::ACTION_REFUND,
'sylius.ui.status' => PaymentRequestInterface::ACTION_STATUS,
'sylius.ui.sync' => PaymentRequestInterface::ACTION_SYNC,
])
->setLabel('sylius.ui.action'),
SelectFilter::create('state', [
'sylius.ui.cancelled' => PaymentRequestInterface::STATE_CANCELLED,
'sylius.ui.completed' => PaymentRequestInterface::STATE_COMPLETED,
'sylius.ui.failed' => PaymentRequestInterface::STATE_FAILED,
'sylius.ui.new' => PaymentRequestInterface::STATE_NEW,
'sylius.ui.processing' => PaymentRequestInterface::STATE_PROCESSING,
])
->setLabel('sylius.ui.state'),
)
->withItemActions(
ShowAction::create()
->setOptions([
'link' => [
'route' => 'sylius_admin_payment_request_show',
'parameters' => [
'hash' => 'resource.hash',
'paymentId' => 'resource.payment.id',
],
],
]),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface PaymentRequestGridInterface
{
public const NAME = 'sylius_admin_payment_request';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,76 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_association_type.class%', name: self::NAME)]
final class ProductAssociationTypeGrid implements ProductAssociationTypeGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createListQueryBuilder', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
])
->addOrderBy('code', 'asc')
->setLimits([10, 25, 50])
->withFields(
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->withOptions([
'vars' => [
'th_class' => 'w-75',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-25',
],
]),
)
->withFilters(
Filter::create('code', 'string')
->setLabel('sylius.ui.code'),
Filter::create('name', 'string')
->setLabel('sylius.ui.name')
->setOptions([
'fields' => [
'translation.name',
],
]),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductAssociationTypeGridInterface
{
public const NAME = 'sylius_admin_product_association_type';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,114 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\SelectFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Attribute\AttributeType\CheckboxAttributeType;
use Sylius\Component\Attribute\AttributeType\DateAttributeType;
use Sylius\Component\Attribute\AttributeType\DatetimeAttributeType;
use Sylius\Component\Attribute\AttributeType\FloatAttributeType;
use Sylius\Component\Attribute\AttributeType\IntegerAttributeType;
use Sylius\Component\Attribute\AttributeType\PercentAttributeType;
use Sylius\Component\Attribute\AttributeType\SelectAttributeType;
use Sylius\Component\Attribute\AttributeType\TextareaAttributeType;
use Sylius\Component\Attribute\AttributeType\TextAttributeType;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_attribute.class%', name: self::NAME)]
final class ProductAttributeGrid implements ProductAttributeGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createListQueryBuilder', [
"expr:service('sylius.context.locale').getLocaleCode()",
])
->setLimits([10, 25, 50])
->addOrderBy('position', 'asc')
->withFields(
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->withOptions([
'vars' => [
'th_class' => 'w-75',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-25',
],
]),
TwigField::create('type', '@SyliusUi/grid/field/label.html.twig')
->setLabel('sylius.ui.type')
->setSortable(true),
TwigField::create('translatable', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.translatable')
->setSortable(true),
TwigField::create('position', '@SyliusUi/grid/field/position.html.twig')
->setLabel('sylius.ui.position')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
)
->withFilters(
StringFilter::create('search', ['translations.name', 'code'])
->setLabel('sylius.ui.search')
->setFormOptions(['type' => StringFilter::TYPE_CONTAINS]),
SelectFilter::create('type', [
'sylius.ui.checkbox' => CheckboxAttributeType::TYPE,
'sylius.ui.date' => DateAttributeType::TYPE,
'sylius.ui.datetime' => DatetimeAttributeType::TYPE,
'sylius.ui.float' => FloatAttributeType::TYPE,
'sylius.ui.integer' => IntegerAttributeType::TYPE,
'sylius.ui.percent' => PercentAttributeType::TYPE,
'sylius.ui.select' => SelectAttributeType::TYPE,
'sylius.ui.text' => TextAttributeType::TYPE,
'sylius.ui.textarea' => TextareaAttributeType::TYPE,
])
->setLabel('sylius.ui.type')
->addFormOption('multiple', true)
->addFormOption('autocomplete', true),
Filter::create('translatable', 'boolean')
->setLabel('sylius.ui.translatable'),
)
->withMainActions(
Action::create('create', 'create_product_attribute'),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductAttributeGridInterface
{
public const NAME = 'sylius_admin_product_attribute';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,171 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\BooleanFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\EntityFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product.class%', name: self::NAME)]
final class ProductGrid implements ProductGridInterface
{
public function __construct(
private readonly string $productClass,
private readonly string $channelClass,
private readonly string $taxonClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createListQueryBuilder', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
])
->setLimits([10, 25, 50])
->addOrderBy('code', 'asc')
->withFields(
TwigField::create('image', '@SyliusAdmin/product/grid/field/product_image.html.twig')
->setLabel('sylius.ui.image')
->setPath('.')
->withOptions([
'vars' => [
'th_class' => 'w-1',
],
]),
TwigField::create('name', '@SyliusAdmin/product/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setSortable(true, 'translation.name')
->withOptions([
'vars' => [
'th_class' => 'w-33',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
TwigField::create('mainTaxon', '@SyliusAdmin/product/grid/field/main_taxon.html.twig')
->setLabel('sylius.ui.main_taxon'),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled'),
)
->withFilters(
StringFilter::create('search', ['code', 'translation.name'])
->setLabel('sylius.ui.search')
->addFormOption('type', StringFilter::TYPE_CONTAINS),
BooleanFilter::create('enabled')
->setLabel('sylius.ui.enabled'),
EntityFilter::create('channel', $this->channelClass, fields: ['channels.id'])
->setLabel('sylius.ui.channel'),
Filter::create('taxon', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.taxon')
->setFormOptions([
'multiple' => false,
'extra_options' => [
'class' => $this->taxonClass,
'translation_fields' => ['name'],
'choice_label' => 'fullname',
],
])
->addOption('fields', ['productTaxons.taxon.id']),
Filter::create('main_taxon', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.main_taxon')
->setFormOptions([
'multiple' => false,
'extra_options' => [
'class' => $this->taxonClass,
'translation_fields' => ['name'],
'choice_label' => 'fullname',
],
])
->addOption('fields', ['mainTaxon.id']),
)
->withMainActions(
Action::create('create', 'links')
->setLabel('sylius.ui.create')
->setOptions([
'class' => 'primary',
'icon' => 'tabler:plus',
'header' => [
'icon' => 'tabler:cube',
'label' => 'sylius.ui.type',
],
'links' => [
'simple' => [
'label' => 'sylius.ui.simple_product',
'route' => 'sylius_admin_product_create_simple',
],
'configurable' => [
'label' => 'sylius.ui.configurable_product',
'route' => 'sylius_admin_product_create',
],
],
]),
)
->withItemActions(
Action::create('details', 'show')
->setLabel('sylius.ui.details'),
UpdateAction::create(),
DeleteAction::create(),
)
->withSubItemActions(
Action::create('variants', 'list')
->setLabel('sylius.ui.variants')
->setOptions([
'links' => [
'index' => [
'label' => 'sylius.ui.list_variants',
'route' => 'sylius_admin_product_variant_index',
'parameters' => [
'productId' => 'resource.id',
],
],
'create' => [
'label' => 'sylius.ui.create',
'route' => 'sylius_admin_product_variant_create',
'parameters' => [
'productId' => 'resource.id',
],
],
'generate' => [
'label' => 'sylius.ui.generate',
'route' => 'sylius_admin_product_variant_generate',
'visible' => 'resource.hasOptions',
'parameters' => [
'productId' => 'resource.id',
],
],
],
]),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
public function getResourceClass(): string
{
return $this->productClass;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductGridInterface
{
public const NAME = 'sylius_admin_product';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,79 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_option.class%', name: self::NAME)]
final class ProductOptionGrid implements ProductOptionGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->setRepositoryMethod('createListQueryBuilder', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
])
->addOrderBy('position', 'asc')
->withFields(
TwigField::create('position', '@SyliusUi/grid/field/position.html.twig')
->setLabel('sylius.ui.position')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setSortable(true, 'translation.name')
->withOptions([
'vars' => [
'th_class' => 'w-75',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-25',
],
]),
)
->withFilters(
StringFilter::create('search', ['code', 'translation.name'])
->setLabel('sylius.ui.search')
->addFormOption('type', StringFilter::TYPE_CONTAINS),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductOptionGridInterface
{
public const NAME = 'sylius_admin_product_option';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,140 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\SelectFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_review.class%', name: self::NAME)]
final class ProductReviewGrid implements ProductReviewGridInterface
{
public function __construct(
private readonly string $productClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('date', 'desc')
->withFields(
TwigField::create('rating', '@SyliusAdmin/product_review/grid/field/rating.html.twig')
->setLabel('sylius.ui.rating')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('author', '@SyliusAdmin/shared/grid/field/customer.html.twig')
->setLabel('sylius.ui.customer'),
StringField::create('title')
->setLabel('sylius.ui.title')
->setSortable(true),
StringField::create('reviewSubject')
->setLabel('sylius.ui.product'),
TwigField::create('date', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.date')
->setPath('createdAt')
->setSortable(true, 'createdAt')
->withOptions([
'vars' => [
'th_class' => 'text-center',
],
]),
TwigField::create('status', '@SyliusAdmin/product_review/grid/field/status.html.twig')
->setLabel('sylius.ui.status')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
)
->withFilters(
Filter::create('title', 'string')
->setLabel('sylius.ui.title'),
SelectFilter::create(
'status',
[
'sylius.ui.new' => 'new',
'sylius.ui.accepted' => 'accepted',
'sylius.ui.rejected' => 'rejected',
],
)
->setLabel('sylius.ui.status'),
Filter::create('product', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.product')
->setFormOptions([
'multiple' => false,
'extra_options' => [
'class' => $this->productClass,
'translation_fields' => ['name'],
'choice_label' => 'name',
],
])
->addOption('fields', ['reviewSubject.id']),
)
->withItemActions(
Action::create('accept', 'apply_transition')
->setLabel('sylius.ui.accept')
->setIcon('tabler:check')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_review_accept',
'parameters' => [
'id' => 'resource.id',
],
],
'class' => 'btn-success btn-icon',
'show_disabled' => false,
'transition' => 'accept',
'graph' => 'sylius_product_review',
]),
Action::create('reject', 'apply_transition')
->setLabel('sylius.ui.reject')
->setIcon('tabler:x')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_review_reject',
'parameters' => [
'id' => 'resource.id',
],
],
'class' => 'btn-warning btn-icon',
'show_disabled' => false,
'transition' => 'reject',
'graph' => 'sylius_product_review',
]),
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductReviewGridInterface
{
public const NAME = 'sylius_admin_product_review';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,171 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField as SyliusTwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\BooleanFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\EntityFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_taxon.class%', name: self::NAME)]
final class ProductTaxonGrid implements ProductTaxonGridInterface
{
public function __construct(
private readonly string $channelClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->addOrderBy('position', 'asc')
->setLimits([10, 25, 50])
->setRepositoryMethod('createListQueryBuilderForTaxon', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
'$taxonId',
])
->withFields(
SyliusTwigField::create('image', '@SyliusAdmin/product/grid/field/product_image.html.twig')
->setLabel('sylius.ui.image')
->setPath('product'),
TwigField::create('name', '@SyliusAdmin/product/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setPath('product')
->setSortable(true, 'product.translations.name')
->withOptions([
'vars' => [
'th_class' => 'w-75',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setPath('product')
->setSortable(true, 'product.code')
->withOptions([
'vars' => [
'th_class' => 'w-25',
],
]),
TwigField::create('mainTaxon', '@SyliusAdmin/product/grid/field/main_taxon.html.twig')
->setLabel('sylius.ui.main_taxon')
->setPath('product.mainTaxon'),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->setPath('product.enabled'),
TwigField::create('position', '@SyliusAdmin/product_taxon/grid/field/position.html.twig')
->setLabel('sylius.ui.position')
->setPath('.')
->setSortable(true),
)
->withFilters(
StringFilter::create('search', ['product.code', 'product.translations.name'])
->setLabel('sylius.ui.search')
->setFormOptions([
'type' => StringFilter::TYPE_CONTAINS,
]),
BooleanFilter::create('enabled')
->setLabel('sylius.ui.enabled')
->setOptions([
'field' => 'product.enabled',
]),
EntityFilter::create('channel', $this->channelClass, fields: ['product.channels.id'])
->setLabel('sylius.ui.channel'),
)
->withMainActions(
Action::create('update_positions', 'update_product_taxon_positions'),
)
->withItemActions(
Action::create('details', 'show')
->setLabel('sylius.ui.details')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_show',
'parameters' => [
'id' => 'resource.product.id',
],
],
]),
Action::create('update', 'update')
->setLabel('sylius.ui.edit')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_update',
'parameters' => [
'id' => 'resource.product.id',
],
],
]),
Action::create('delete', 'delete')
->setLabel('sylius.ui.delete')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_delete',
'parameters' => [
'id' => 'resource.product.id',
],
],
]),
)
->withSubItemActions(
Action::create('variants', 'list')
->setLabel('sylius.ui.variants')
->setOptions([
'links' => [
'index' => [
'label' => 'sylius.ui.list_variants',
'route' => 'sylius_admin_product_variant_index',
'parameters' => [
'productId' => 'resource.product.id',
],
],
'create' => [
'label' => 'sylius.ui.create',
'route' => 'sylius_admin_product_variant_create',
'parameters' => [
'productId' => 'resource.product.id',
],
],
'generate' => [
'label' => 'sylius.ui.generate',
'route' => 'sylius_admin_product_variant_generate',
'visible' => 'resource.product.hasOptions',
'parameters' => [
'productId' => 'resource.product.id',
],
],
],
]),
)
->withBulkActions(
Action::create('delete', 'delete')
->setLabel('sylius.ui.delete_products')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_taxon_bulk_delete_products',
'parameters' => [
'taxonId' => '$taxonId',
],
],
]),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductTaxonGridInterface
{
public const NAME = 'sylius_admin_product_taxon';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,132 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\ActionGroup;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_variant.class%', name: self::NAME)]
final class ProductVariantGrid implements ProductVariantGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->setRepositoryMethod('createQueryBuilderByProductId', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
'$productId',
])
->addOrderBy('position', 'asc')
->withFields(
TwigField::create('name', '@SyliusAdmin/product_variant/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setPath('.'),
StringField::create('code')
->setLabel('sylius.ui.code'),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->withOptions([
'vars' => [
'th_class' => 'text-center',
],
]),
TwigField::create('inventory', '@SyliusAdmin/product_variant/grid/field/inventory.html.twig')
->setLabel('sylius.ui.inventory')
->setPath('.')
->withOptions([
'vars' => [
'th_class' => 'text-center',
],
]),
TwigField::create('position', '@SyliusAdmin/product_variant/grid/field/position.html.twig')
->setLabel('sylius.ui.position')
->setPath('.')
->setSortable(true, 'position')
->withOptions([
'vars' => [
'th_class' => 'text-center',
],
]),
)
->withFilters(
Filter::create('code', 'string')
->setLabel('sylius.ui.code'),
Filter::create('name', 'string')
->setLabel('sylius.ui.name')
->setOptions([
'fields' => [
'translation.name',
],
]),
)
->withMainActions(
Action::create('generate', 'generate_variants')
->setOptions([
'product' => 'expr:service(\'sylius.repository.product\').find($productId)',
]),
Action::create('update_positions', 'update_product_variant_positions'),
CreateAction::create()
->setOptions([
'link' => [
'parameters' => [
'productId' => '$productId',
],
],
]),
)
->withItemActions(
UpdateAction::create([
'link' => [
'parameters' => [
'id' => 'resource.id',
'productId' => '$productId',
],
],
]),
DeleteAction::create([
'link' => [
'parameters' => [
'id' => 'resource.id',
'productId' => '$productId',
],
],
]),
)
->withBulkActions(
DeleteAction::create([
'link' => [
'parameters' => [
'productId' => '$productId',
],
],
]),
)
->addActionGroup(
ActionGroup::create(
'subitem',
Action::create('price_history', 'price_history')
->setLabel('sylius.ui.price_history'),
),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductVariantGridInterface
{
public const NAME = 'sylius_admin_product_variant';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,84 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product_variant.class%', name: self::NAME)]
final class ProductVariantWithCatalogPromotionGrid implements ProductVariantWithCatalogPromotionGridInterface
{
public function __construct(
private readonly string $locale,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->setRepositoryMethod('createCatalogPromotionListQueryBuilder', [
$this->locale,
'expr:notFoundOnNull(service("sylius.repository.catalog_promotion").find($id))',
])
->addOrderBy('code', 'asc')
->withFields(
TwigField::create('name', '@SyliusAdmin/product_variant/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setPath('.'),
StringField::create('code')
->setLabel('sylius.ui.code'),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled'),
TwigField::create('inventory', '@SyliusAdmin/product_variant/grid/field/inventory.html.twig')
->setLabel('sylius.ui.inventory')
->setPath('.'),
)
->withFilters(
Filter::create('code', 'string')
->setLabel('sylius.ui.code'),
StringFilter::create('name', ['translation.name'])
->setLabel('sylius.ui.name'),
)
->withItemActions(
Action::create('show_product', 'show')
->setOptions([
'link' => [
'route' => 'sylius_admin_product_show',
'parameters' => [
'id' => 'resource.product.id',
],
],
])
->setLabel('sylius.ui.show_product'),
UpdateAction::create([
'link' => [
'parameters' => [
'id' => 'resource.id',
'productId' => 'resource.product.id',
],
],
]),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductVariantWithCatalogPromotionGridInterface
{
public const NAME = 'sylius_admin_product_variant_with_catalog_promotion';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,111 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\DateTimeField;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.promotion_coupon.class%', name: self::NAME)]
final class PromotionCouponGrid implements PromotionCouponGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->orderBy('used', 'desc')
->setRepositoryMethod('createQueryBuilderByPromotionId', [
'promotionId' => '$promotionId',
])
->withFields(
StringField::create('code')
->setLabel('sylius.ui.code')
->setSortable(true),
StringField::create('usageLimit')
->setLabel('sylius.ui.usage_limit')
->setSortable(true),
StringField::create('perCustomerUsageLimit')
->setLabel('sylius.ui.per_customer_usage_limit')
->setSortable(true),
TwigField::create('used', '@SyliusAdmin/promotion_coupon/grid/field/used.html.twig')
->setLabel('sylius.ui.used')
->setSortable(true)
->setPath('.'),
DateTimeField::create('expiresAt')
->setLabel('sylius.ui.expires_at')
->setSortable(true)
->setOption('format', 'd-m-Y'),
)
->withFilters(
Filter::create('code', 'string')
->setLabel('sylius.ui.code'),
)
->withMainActions(
Action::create('generate', 'default')
->setLabel('sylius.ui.generate')
->setIcon('tabler:arrows-split')
->setOptions([
'link' => [
'route' => 'sylius_admin_promotion_coupon_generate',
'parameters' => [
'promotionId' => '$promotionId',
],
],
]),
CreateAction::create()
->setOptions([
'link' => [
'parameters' => [
'promotionId' => '$promotionId',
],
],
]),
)
->withItemActions(
UpdateAction::create([
'link' => [
'parameters' => [
'id' => 'resource.id',
'promotionId' => '$promotionId',
],
],
]),
DeleteAction::create([
'link' => [
'parameters' => [
'id' => 'resource.id',
'promotionId' => '$promotionId',
],
],
]),
)
->withBulkActions(
DeleteAction::create([
'link' => [
'parameters' => [
'promotionId' => '$promotionId',
],
],
]),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface PromotionCouponGridInterface
{
public const NAME = 'sylius_admin_promotion_coupon';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,135 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\ActionGroup\ActionGroup;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\ExistsFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.promotion.class%', name: self::NAME)]
final class PromotionGrid implements PromotionGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('priority', 'desc')
->withFields(
TwigField::create('priority', '@SyliusAdmin/promotion/grid/field/priority.html.twig')
->setLabel('sylius.ui.priority')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('name', '@SyliusUi/grid/field/name_and_description.html.twig')
->setLabel('sylius.ui.name')
->setPath('.')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-100',
],
]),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
TwigField::create('couponBased', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.coupons')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('usage', '@SyliusAdmin/promotion/grid/field/usage.html.twig')
->setLabel('sylius.ui.usage')
->setPath('.')
->setSortable(true, 'used'),
)
->withFilters(
StringFilter::create('search', ['code', 'name'])
->setLabel('sylius.ui.search'),
Filter::create('couponBased', 'boolean')
->setLabel('sylius.ui.coupon_based'),
Filter::create('coupon_code', 'string')
->setLabel('sylius.ui.coupon')
->setOptions([
'fields' => [
'coupons.code',
],
]),
ExistsFilter::create('archival', 'archivedAt')
->setLabel('sylius.ui.archival')
->setDefaultValue(false),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
Action::create('archive', 'archive'),
)
->addActionGroup(
ActionGroup::create(
'subitem',
Action::create('coupons', 'list')
->setLabel('sylius.ui.manage_coupons')
->setOptions([
'visible' => 'resource.couponBased',
'links' => [
'index' => [
'label' => 'sylius.ui.list_coupons',
'route' => 'sylius_admin_promotion_coupon_index',
'parameters' => [
'promotionId' => 'resource.id',
],
],
'create' => [
'label' => 'sylius.ui.create',
'route' => 'sylius_admin_promotion_coupon_create',
'parameters' => [
'promotionId' => 'resource.id',
],
],
'generate' => [
'label' => 'sylius.ui.generate',
'route' => 'sylius_admin_promotion_coupon_generate',
'parameters' => [
'promotionId' => 'resource.id',
],
],
],
]),
),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface PromotionGridInterface
{
public const NAME = 'sylius_admin_promotion';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,117 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\ShowAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\SelectFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.shipment.class%', name: self::NAME)]
final class ShipmentGrid implements ShipmentGridInterface
{
public function __construct(
private readonly string $channelClass,
private readonly string $shippingMethodClass,
) {
}
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->setRepositoryMethod('createListQueryBuilder')
->addOrderBy('createdAt', 'desc')
->withFields(
TwigField::create('createdAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.created_at')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('shippedAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.shipped_at')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('order', '@SyliusAdmin/shared/grid/field/order_number.html.twig')
->setLabel('sylius.ui.order')
->setPath('order')
->withOptions([
'vars' => [
'th_class' => 'w-1',
],
]),
TwigField::create('channel', '@SyliusAdmin/shared/grid/field/channel.html.twig')
->setLabel('sylius.ui.channel')
->setPath('order.channel'),
TwigField::create('state', '@SyliusAdmin/shared/grid/field/shipment_state.html.twig')
->setLabel('sylius.ui.state')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
)
->withFilters(
SelectFilter::create('state', [
'sylius.ui.cancelled' => 'cancelled',
'sylius.ui.ready' => 'ready',
'sylius.ui.shipped' => 'shipped',
])
->setLabel('sylius.ui.state'),
Filter::create('channel', 'ux_autocomplete')
->setLabel('sylius.ui.channel')
->setOptions([
'fields' => [
'order.channel.id',
],
])
->setFormOptions([
'extra_options' => [
'class' => $this->channelClass,
'choice_label' => 'name',
],
]),
Filter::create('method', 'ux_translatable_autocomplete')
->setLabel('sylius.ui.method')
->setOptions([
'fields' => [
'method.id',
],
])
->setFormOptions([
'extra_options' => [
'class' => $this->shippingMethodClass,
'translation_fields' => ['name'],
'choice_label' => 'name',
],
]),
)
->withItemActions(
Action::create('ship', 'ship_with_tracking_code'),
ShowAction::create(),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ShipmentGridInterface
{
public const NAME = 'sylius_admin_shipment';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,74 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.shipping_category.class%', name: self::NAME)]
final class ShippingCategoryGrid implements ShippingCategoryGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->setRepositoryMethod('createListQueryBuilder')
->withFields(
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code'),
TwigField::create('createdAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.creation_date')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
TwigField::create('updatedAt', '@SyliusAdmin/shared/grid/field/date.html.twig')
->setLabel('sylius.ui.updating_date')
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
],
]),
)
->withFilters(
Filter::create('search', 'string')
->setLabel('sylius.ui.search')
->setOptions([
'fields' => [
'code',
'name',
],
]),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ShippingCategoryGridInterface
{
public const NAME = 'sylius_admin_shipping_category';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,85 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\ExistsFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.shipping_method.class%', name: self::NAME)]
final class ShippingMethodGrid implements ShippingMethodGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->setRepositoryMethod('createListQueryBuilder', [
'expr:service(\'sylius.context.locale\').getLocaleCode()',
])
->addOrderBy('position', 'asc')
->withFields(
TwigField::create('position', '@SyliusUi/grid/field/position.html.twig')
->setLabel('sylius.ui.position')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setSortable(true, 'translation.name'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
StringField::create('zone')
->setLabel('sylius.ui.zone'),
TwigField::create('enabled', '@SyliusAdmin/shared/grid/field/boolean.html.twig')
->setLabel('sylius.ui.enabled')
->setSortable(true),
)
->withFilters(
StringFilter::create('search', ['code', 'translation.name'])
->setLabel('sylius.ui.search'),
Filter::create('enabled', 'boolean')
->setLabel('sylius.ui.enabled'),
ExistsFilter::create('archival', 'archivedAt')
->setLabel('sylius.ui.archival')
->setDefaultValue(false),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
Action::create('archive', 'archive'),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ShippingMethodGridInterface
{
public const NAME = 'sylius_admin_shipping_method';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,61 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.tax_category.class%', name: self::NAME)]
final class TaxCategoryGrid implements TaxCategoryGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('nameAndDescription', 'asc')
->withFields(
TwigField::create('nameAndDescription', '@SyliusUi/grid/field/name_and_description.html.twig')
->setLabel('sylius.ui.name')
->setPath('.')
->setSortable(true, 'name'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
)
->withFilters(
StringFilter::create('search', ['code', 'name'])
->setLabel('sylius.ui.search')
->addFormOption('type', StringFilter::TYPE_CONTAINS),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface TaxCategoryGridInterface
{
public const NAME = 'sylius_admin_tax_category';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,78 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\CreateAction;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\DateFilter;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.tax_rate.class%', name: self::NAME)]
final class TaxRateGrid implements TaxRateGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('name', 'asc')
->withFields(
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name')
->setSortable(true),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code')
->setSortable(true),
StringField::create('zone')
->setLabel('sylius.ui.zone'),
StringField::create('category')
->setLabel('sylius.ui.category'),
TwigField::create('amount', '@SyliusUi/grid/field/percent.html.twig')
->setLabel('sylius.ui.amount')
->setSortable(true),
)
->withFilters(
Filter::create('startDate', 'date')
->setLabel('sylius.ui.start_date')
->setOptions([
'inclusive_to' => true,
]),
DateFilter::create('endDate')
->setLabel('sylius.ui.end_date')
->setOptions([
'inclusive_to' => true,
]),
StringFilter::create('search', ['code', 'name'])
->setLabel('sylius.ui.search'),
)
->withMainActions(
CreateAction::create(),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface TaxRateGridInterface
{
public const NAME = 'sylius_admin_tax_rate';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,35 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.taxon.class%', name: self::NAME)]
final class TaxonGrid implements TaxonGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createListQueryBuilder')
->setLimits([10, 25, 50])
->withFilters(
StringFilter::create('code', ['code']),
StringFilter::create('name', ['translation.name']),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface TaxonGridInterface
{
public const NAME = 'sylius_admin_taxon';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,105 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Action\DeleteAction;
use Sylius\Bundle\GridBundle\Builder\Action\UpdateAction;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\Filter\StringFilter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.zone.class%', name: self::NAME)]
final class ZoneGrid implements ZoneGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setLimits([10, 25, 50])
->addOrderBy('priority', 'desc')
->withFields(
TwigField::create('priority', '@SyliusAdmin/zone/grid/field/priority.html.twig')
->setLabel('sylius.ui.priority')
->setSortable(true)
->withOptions([
'vars' => [
'th_class' => 'w-1 text-center',
'td_class' => 'text-center',
],
]),
TwigField::create('name', '@SyliusAdmin/shared/grid/field/name.html.twig')
->setLabel('sylius.ui.name'),
TwigField::create('code', '@SyliusAdmin/shared/grid/field/code.html.twig')
->setLabel('sylius.ui.code'),
TwigField::create('type', '@SyliusAdmin/zone/grid/field/type.html.twig')
->setLabel('sylius.ui.type'),
)
->withFilters(
StringFilter::create('name')
->setLabel('sylius.ui.name'),
StringFilter::create('code')
->setLabel('sylius.ui.code'),
)
->withMainActions(
Action::create('create', 'links')
->setLabel('sylius.ui.create')
->setOptions([
'class' => 'primary',
'icon' => 'tabler:plus',
'header' => [
'icon' => 'tabler:cube',
'label' => 'sylius.ui.type',
],
'links' => [
'country' => [
'label' => 'sylius.ui.zone_consisting_of_countries',
'icon' => 'tabler:plus',
'route' => 'sylius_admin_zone_create',
'parameters' => [
'type' => 'country',
],
],
'province' => [
'label' => 'sylius.ui.zone_consisting_of_provinces',
'icon' => 'tabler:plus',
'route' => 'sylius_admin_zone_create',
'parameters' => [
'type' => 'province',
],
],
'zone' => [
'label' => 'sylius.ui.zone_consisting_of_other_zones',
'icon' => 'tabler:plus',
'route' => 'sylius_admin_zone_create',
'parameters' => [
'type' => 'zone',
],
],
],
]),
)
->withItemActions(
UpdateAction::create(),
DeleteAction::create(),
)
->withBulkActions(
DeleteAction::create(),
)
;
}
}

View file

@ -0,0 +1,24 @@
<?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\AdminBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ZoneGridInterface
{
public const NAME = 'sylius_admin_zone';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -15,6 +15,72 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Sylius\Bundle\AdminBundle\Form\Type\Grid\Filter\UxAutocompleteFilterType; use Sylius\Bundle\AdminBundle\Form\Type\Grid\Filter\UxAutocompleteFilterType;
use Sylius\Bundle\AdminBundle\Form\Type\Grid\Filter\UxTranslatableAutocompleteFilterType; use Sylius\Bundle\AdminBundle\Form\Type\Grid\Filter\UxTranslatableAutocompleteFilterType;
use Sylius\Bundle\AdminBundle\Grid\AdminUserGrid;
use Sylius\Bundle\AdminBundle\Grid\AdminUserGridInterface;
use Sylius\Bundle\AdminBundle\Grid\CatalogPromotionGrid;
use Sylius\Bundle\AdminBundle\Grid\CatalogPromotionGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ChannelGrid;
use Sylius\Bundle\AdminBundle\Grid\ChannelGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ChannelPricingLogEntryGrid;
use Sylius\Bundle\AdminBundle\Grid\ChannelPricingLogEntryGridInterface;
use Sylius\Bundle\AdminBundle\Grid\CountryGrid;
use Sylius\Bundle\AdminBundle\Grid\CountryGridInterface;
use Sylius\Bundle\AdminBundle\Grid\CurrencyGrid;
use Sylius\Bundle\AdminBundle\Grid\CurrencyGridInterface;
use Sylius\Bundle\AdminBundle\Grid\CustomerGrid;
use Sylius\Bundle\AdminBundle\Grid\CustomerGridInterface;
use Sylius\Bundle\AdminBundle\Grid\CustomerGroupGrid;
use Sylius\Bundle\AdminBundle\Grid\CustomerGroupGridInterface;
use Sylius\Bundle\AdminBundle\Grid\CustomerOrderGrid;
use Sylius\Bundle\AdminBundle\Grid\CustomerOrderGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ExchangeRateGrid;
use Sylius\Bundle\AdminBundle\Grid\ExchangeRateGridInterface;
use Sylius\Bundle\AdminBundle\Grid\InventoryGrid;
use Sylius\Bundle\AdminBundle\Grid\InventoryGridInterface;
use Sylius\Bundle\AdminBundle\Grid\LocaleGrid;
use Sylius\Bundle\AdminBundle\Grid\LocaleGridInterface;
use Sylius\Bundle\AdminBundle\Grid\OrderGrid;
use Sylius\Bundle\AdminBundle\Grid\OrderGridInterface;
use Sylius\Bundle\AdminBundle\Grid\PaymentGrid;
use Sylius\Bundle\AdminBundle\Grid\PaymentGridInterface;
use Sylius\Bundle\AdminBundle\Grid\PaymentMethodGrid;
use Sylius\Bundle\AdminBundle\Grid\PaymentMethodGridInterface;
use Sylius\Bundle\AdminBundle\Grid\PaymentRequestGrid;
use Sylius\Bundle\AdminBundle\Grid\PaymentRequestGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductAssociationTypeGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductAssociationTypeGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductAttributeGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductAttributeGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductOptionGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductOptionGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductReviewGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductReviewGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductTaxonGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductTaxonGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductVariantGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductVariantGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ProductVariantWithCatalogPromotionGrid;
use Sylius\Bundle\AdminBundle\Grid\ProductVariantWithCatalogPromotionGridInterface;
use Sylius\Bundle\AdminBundle\Grid\PromotionCouponGrid;
use Sylius\Bundle\AdminBundle\Grid\PromotionCouponGridInterface;
use Sylius\Bundle\AdminBundle\Grid\PromotionGrid;
use Sylius\Bundle\AdminBundle\Grid\PromotionGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ShipmentGrid;
use Sylius\Bundle\AdminBundle\Grid\ShipmentGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ShippingCategoryGrid;
use Sylius\Bundle\AdminBundle\Grid\ShippingCategoryGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ShippingMethodGrid;
use Sylius\Bundle\AdminBundle\Grid\ShippingMethodGridInterface;
use Sylius\Bundle\AdminBundle\Grid\TaxCategoryGrid;
use Sylius\Bundle\AdminBundle\Grid\TaxCategoryGridInterface;
use Sylius\Bundle\AdminBundle\Grid\TaxRateGrid;
use Sylius\Bundle\AdminBundle\Grid\TaxRateGridInterface;
use Sylius\Bundle\AdminBundle\Grid\TaxonGrid;
use Sylius\Bundle\AdminBundle\Grid\TaxonGridInterface;
use Sylius\Bundle\AdminBundle\Grid\ZoneGrid;
use Sylius\Bundle\AdminBundle\Grid\ZoneGridInterface;
use Sylius\Component\Grid\Filter\EntityFilter; use Sylius\Component\Grid\Filter\EntityFilter;
return static function (ContainerConfigurator $container) { return static function (ContainerConfigurator $container) {
@ -29,4 +95,216 @@ return static function (ContainerConfigurator $container) {
->set('sylius_admin.grid_filter.ux_translatable_autocomplete', EntityFilter::class) ->set('sylius_admin.grid_filter.ux_translatable_autocomplete', EntityFilter::class)
->tag('sylius.grid_filter', ['type' => 'ux_translatable_autocomplete', 'form_type' => UxTranslatableAutocompleteFilterType::class]) ->tag('sylius.grid_filter', ['type' => 'ux_translatable_autocomplete', 'form_type' => UxTranslatableAutocompleteFilterType::class])
; ;
$services->set('sylius_admin.grid.admin_user', AdminUserGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(AdminUserGridInterface::class, 'sylius_admin.grid.admin_user');
$services->set('sylius_admin.grid.catalog_promotion', CatalogPromotionGrid::class)
->args([
'%sylius.model.channel.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(CatalogPromotionGridInterface::class, 'sylius_admin.grid.catalog_promotion');
$services->set('sylius_admin.grid.channel', ChannelGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ChannelGridInterface::class, 'sylius_admin.grid.channel');
$services->set('sylius_admin.grid.currency', CurrencyGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(CurrencyGridInterface::class, 'sylius_admin.grid.currency');
$services->set('sylius_admin.grid.customer', CustomerGrid::class)
->args([
'%sylius.model.customer_group.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(CustomerGridInterface::class, 'sylius_admin.grid.customer');
$services->set('sylius_admin.grid.customer_group', CustomerGroupGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(CustomerGroupGridInterface::class, 'sylius_admin.grid.customer_group');
$services->set('sylius_admin.grid.locale', LocaleGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(LocaleGridInterface::class, 'sylius_admin.grid.locale');
$services->set('sylius_admin.grid.inventory', InventoryGrid::class)
->args([
'%sylius.model.product.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(InventoryGridInterface::class, 'sylius_admin.grid.inventory');
$services->set('sylius_admin.grid.payment_method', PaymentMethodGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(PaymentMethodGridInterface::class, 'sylius_admin.grid.payment_method');
$services->set('sylius_admin.grid.product_association_type', ProductAssociationTypeGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ProductAssociationTypeGridInterface::class, 'sylius_admin.grid.product_association_type');
$services->set('syllabus_admin.grid.taxon', TaxonGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(TaxonGridInterface::class, 'sylius_admin.grid.taxon');
$services->set('sylius_admin.grid.product_taxon', ProductTaxonGrid::class)
->args([
'%sylius.model.channel.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(ProductTaxonGridInterface::class, 'sylius_admin.grid.product_taxon');
$services->set('sylius_admin.grid.product', ProductGrid::class)
->args([
'%sylius.model.product.class%',
'%sylius.model.channel.class%',
'%sylius.model.taxon.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(ProductGridInterface::class, 'sylius_admin.grid.product');
$services->set('sylius_admin.grid.product_attribute', ProductAttributeGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ProductAttributeGridInterface::class, 'sylius_admin.grid.product_attribute');
$services->set('sylius_admin.grid.product_variant', ProductVariantGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ProductVariantGridInterface::class, 'sylius_admin.grid.product_variant');
$services->set('sylius_admin.grid.product_variant_with_catalog_promotion', ProductVariantWithCatalogPromotionGrid::class)
->args([
'%locale%',
])
->tag('sylius.invokable_grid')
;
$services->alias(ProductVariantWithCatalogPromotionGridInterface::class, 'sylius_admin.grid.product_variant_with_catalog_promotion');
$services->set('sylius_admin.grid.country', CountryGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(CountryGridInterface::class, 'sylius_admin.grid.country');
$services->set('sylius_admin.grid.shipment', ShipmentGrid::class)
->args([
'%sylius.model.channel.class%',
'%sylius.model.shipping_method.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(ShipmentGridInterface::class, 'sylius_admin.grid.shipment');
$services->set('sylius_admin.grid.shipping_category', ShippingCategoryGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ShippingCategoryGridInterface::class, 'sylius_admin.grid.shipping_category');
$services->set('sylius_admin.grid.shipping_method', ShippingMethodGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ShippingMethodGridInterface::class, 'sylius_admin.grid.shipping_method');
$services->set('sylius_admin.grid.tax_category', TaxCategoryGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(TaxCategoryGridInterface::class, 'sylius_admin.grid.tax_category');
$services->set('sylius_admin.grid.tax_rate', TaxRateGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(TaxRateGridInterface::class, 'sylius_admin.grid.tax_rate');
$services->set('sylius_admin.grid.promotion_coupon', PromotionCouponGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(PromotionCouponGridInterface::class, 'sylius_admin.grid.promotion_coupon');
$services->set('sylius_admin.grid.promotion', PromotionGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(PromotionGridInterface::class, 'sylius_admin.grid.promotion');
$services->set('sylius_admin.grid.zone', ZoneGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ZoneGridInterface::class, 'sylius_admin.grid.zone');
$services->set('sylius_admin.grid.payment', PaymentGrid::class)
->args([
'%sylius.model.channel.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(PaymentGridInterface::class, 'sylius_admin.grid.payment');
$services->set('sylius_admin.grid.customer_order', CustomerOrderGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(CustomerOrderGridInterface::class, 'sylius_admin.grid.customer_order');
$services->set('sylius_admin.grid.order', OrderGrid::class)
->args([
'%sylius.model.channel.class%',
'%sylius.model.customer.class%',
'%sylius.model.product.class%',
'%sylius.model.product_variant.class%',
'%sylius.model.shipping_method.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(OrderGridInterface::class, 'sylius_admin.grid.order');
$services->set('sylius_admin.grid.exchange_rate', ExchangeRateGrid::class)
->args([
'%sylius.model.currency.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(ExchangeRateGridInterface::class, 'sylius_admin.grid.exchange_rate');
$services->set('sylius_admin.grid.product_option', ProductOptionGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ProductOptionGridInterface::class, 'sylius_admin.grid.product_option');
$services->set('sylius_admin.grid.product_review', ProductReviewGrid::class)
->args([
'%sylius.model.product.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(ProductReviewGridInterface::class, 'sylius_admin.grid.product_review');
$services->set('sylius_admin.grid.channel_pricing_log_entry', ChannelPricingLogEntryGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(ChannelPricingLogEntryGridInterface::class, 'sylius_admin.grid.channel_pricing_log_entry');
$services->set('sylius_admin.grid.payment_request', PaymentRequestGrid::class)
->args([
'%sylius.model.payment_method.class%',
])
->tag('sylius.invokable_grid')
;
$services->alias(PaymentRequestGridInterface::class, 'sylius_admin.grid.payment_request');
}; };

View file

@ -146,6 +146,20 @@ final class Configuration implements ConfigurationInterface
->prototype('scalar')->end() ->prototype('scalar')->end()
->defaultValue([PaymentInterface::STATE_NEW, PaymentInterface::STATE_CART]) ->defaultValue([PaymentInterface::STATE_NEW, PaymentInterface::STATE_CART])
->end() ->end()
->end()
->end()
->end()
->end()
->arrayNode('grid')
->addDefaultsIfNotSet()
->children()
->booleanNode('use_legacy_config')->defaultNull()->end()
->arrayNode('grids')
->useAttributeAsKey('grid_code')
->arrayPrototype()
->children()
->booleanNode('use_legacy_config')->defaultTrue()->end()
->end()
->end() ->end()
->end() ->end()
->end() ->end()

View file

@ -79,6 +79,7 @@ final class SyliusCoreExtension extends AbstractResourceExtension implements Pre
$container->setParameter('sylius_core.max_int_value', $config['max_int_value']); $container->setParameter('sylius_core.max_int_value', $config['max_int_value']);
$container->setParameter('sylius_core.allowed_images_mime_types', $config['allowed_images_mime_types']); $container->setParameter('sylius_core.allowed_images_mime_types', $config['allowed_images_mime_types']);
$container->setParameter('sylius_core.checkout.payment.allowed_states', $config['checkout']['payment']['allowed_states']); $container->setParameter('sylius_core.checkout.payment.allowed_states', $config['checkout']['payment']['allowed_states']);
$container->setParameter('sylius_core.grids_configuration', $config['grid']);
/** @var string $env */ /** @var string $env */
$env = $container->getParameter('kernel.environment'); $env = $container->getParameter('kernel.environment');

View file

@ -0,0 +1,48 @@
<?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\CoreBundle\Grid\Provider;
use Sylius\Component\Grid\Definition\Grid;
use Sylius\Component\Grid\Exception\UndefinedGridException;
use Sylius\Component\Grid\Provider\GridProviderInterface;
/**
* From 3.0 forward Sylius does not support the chain provider and only use Service grids. This is a BC layer for
* allowing users to migrate on a per grid basis to the new configuration.
*
* @deprecated will be removed in 3.0
*/
final class OverrideGridProvider implements GridProviderInterface
{
/** @param array<string, mixed> $configuration */
public function __construct(
private array $configuration,
private GridProviderInterface $chainGridProvider,
private GridProviderInterface $arrayGridProvider,
) {
}
public function get(string $code): Grid
{
$useYamlGrid = $this->configuration['use_legacy_config'] ?? $this->configuration['grids'][$code]['use_legacy_config'] ?? true;
if ($useYamlGrid) {
try {
return $this->arrayGridProvider->get($code);
} catch(UndefinedGridException) {
}
}
return $this->chainGridProvider->get($code);
}
}

View file

@ -123,7 +123,7 @@ final class ExtensionsRequirements extends RequirementCollection
if (extension_loaded('intl')) { if (extension_loaded('intl')) {
if (defined('INTL_ICU_VERSION')) { if (defined('INTL_ICU_VERSION')) {
$version = \INTL_ICU_VERSION; $version = INTL_ICU_VERSION;
} else { } else {
$reflector = new ReflectionExtension('intl'); $reflector = new ReflectionExtension('intl');

View file

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace Symfony\Component\DependencyInjection\Loader\Configurator; namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use Sylius\Bundle\CoreBundle\Grid\Provider\OverrideGridProvider;
use Sylius\Bundle\CoreBundle\Provider\ChannelBasedDefaultTaxZoneProvider; use Sylius\Bundle\CoreBundle\Provider\ChannelBasedDefaultTaxZoneProvider;
use Sylius\Bundle\CoreBundle\Provider\ChannelBasedProductTranslationProvider; use Sylius\Bundle\CoreBundle\Provider\ChannelBasedProductTranslationProvider;
use Sylius\Bundle\CoreBundle\Provider\ChannelBasedProductTranslationProviderInterface; use Sylius\Bundle\CoreBundle\Provider\ChannelBasedProductTranslationProviderInterface;
@ -136,4 +137,13 @@ return static function (ContainerConfigurator $container) {
->args([service('sylius.repository.order')]) ->args([service('sylius.repository.order')])
->tag('sylius.statistics.orders_count_provider', ['type' => 'year']) ->tag('sylius.statistics.orders_count_provider', ['type' => 'year'])
; ;
$services->set('sylius.provider.override_grid_provider', OverrideGridProvider::class)
->decorate('sylius.grid.chain_provider')
->args([
'%sylius_core.grids_configuration%',
service('sylius.provider.override_grid_provider.inner'),
service('sylius.grid.array_grid_provider'),
])
;
}; };

View file

@ -42,7 +42,7 @@
"sylius/currency-bundle": "^2.0", "sylius/currency-bundle": "^2.0",
"sylius/customer-bundle": "^2.0", "sylius/customer-bundle": "^2.0",
"sylius/fixtures-bundle": "^1.9", "sylius/fixtures-bundle": "^1.9",
"sylius/grid-bundle": "^1.13", "sylius/grid-bundle": "^1.16@alpha",
"sylius/inventory-bundle": "^2.0", "sylius/inventory-bundle": "^2.0",
"sylius/locale-bundle": "^2.0", "sylius/locale-bundle": "^2.0",
"sylius/mailer-bundle": "^2.1", "sylius/mailer-bundle": "^2.1",

View file

@ -0,0 +1,140 @@
<?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 Tests\Sylius\Bundle\CoreBundle\Grid\Provider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Sylius\Bundle\CoreBundle\Grid\Provider\OverrideGridProvider;
use Sylius\Component\Grid\Definition\Grid;
use Sylius\Component\Grid\Exception\UndefinedGridException;
use Sylius\Component\Grid\Provider\GridProviderInterface;
final class OverrideGridProviderTest extends TestCase
{
private GridProviderInterface&MockObject $chainProvider;
private GridProviderInterface&MockObject $arrayProvider;
private Grid $gridDefinition;
protected function setUp(): void
{
$this->chainProvider = $this->createMock(GridProviderInterface::class);
$this->arrayProvider = $this->createMock(GridProviderInterface::class);
$this->gridDefinition = Grid::fromCodeAndDriverConfiguration('app_book', '', []);
}
public function test_use_override_for_grid(): void
{
$this->arrayProvider
->expects($this->never())
->method('get')
;
$this->chainProvider
->expects($this->once())
->method('get')
->with('app_book')
->willReturn($this->gridDefinition)
;
$configurableProvider = new OverrideGridProvider(
[
'grids' => [
'app_book' => ['use_legacy_config' => false],
],
],
$this->chainProvider,
$this->arrayProvider,
);
$gridDefinition = $configurableProvider->get('app_book');
self::assertEquals($this->gridDefinition, $gridDefinition);
}
public function test_overriding_for_all_grids(): void
{
$this->arrayProvider
->expects($this->never())
->method('get')
;
$this->chainProvider
->expects($this->once())
->method('get')
->with('app_book')
->willReturn($this->gridDefinition)
;
$configurableProvider = new OverrideGridProvider(
['use_legacy_config' => false],
$this->chainProvider,
$this->arrayProvider,
);
$gridDefinition = $configurableProvider->get('app_book');
self::assertEquals($this->gridDefinition, $gridDefinition);
}
public function test_using_the_array_provider_by_default(): void
{
$this->arrayProvider
->expects($this->once())
->method('get')
->with('app_book')
->willReturn($this->gridDefinition)
;
$this->chainProvider
->expects($this->never())
->method('get')
;
$configurableProvider = new OverrideGridProvider(
[],
$this->chainProvider,
$this->arrayProvider,
);
$gridDefinition = $configurableProvider->get('app_book');
self::assertEquals($this->gridDefinition, $gridDefinition);
}
public function test_fallback_if_no_yaml_grid_is_configured(): void
{
$this->arrayProvider
->expects($this->once())
->method('get')
->with('app_book')
->willThrowException(new UndefinedGridException('app_book'))
;
$this->chainProvider
->expects($this->once())
->method('get')
->with('app_book')
->willReturn($this->gridDefinition)
;
$configurableProvider = new OverrideGridProvider(
[],
$this->chainProvider,
$this->arrayProvider,
);
$gridDefinition = $configurableProvider->get('app_book');
self::assertEquals($this->gridDefinition, $gridDefinition);
}
}

View file

@ -0,0 +1,78 @@
<?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\ShopBundle\Grid\Account;
use Sylius\Bundle\GridBundle\Builder\Action\Action;
use Sylius\Bundle\GridBundle\Builder\Field\DateTimeField;
use Sylius\Bundle\GridBundle\Builder\Field\TwigField;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.order.class%', name: self::NAME)]
final class OrderGrid implements OrderGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createByCustomerAndChannelIdQueryBuilder', [
"expr:service('sylius.context.customer').getCustomer().getId()",
"expr:service('sylius.context.channel').getChannel().getId()",
])
->orderBy('checkoutCompletedAt', 'desc')
->setLimits([10, 25, 50])
->withFields(
TwigField::create('number', '@SyliusShop/account/order/grid/field/number.html.twig')
->setLabel('sylius.ui.number')
->setSortable(true),
DateTimeField::create('checkoutCompletedAt', 'm/d/Y')
->setLabel('sylius.ui.date'),
TwigField::create('shippingAddress', '@SyliusShop/account/order/grid/field/address.html.twig')
->setLabel('sylius.ui.ship_to'),
TwigField::create('total', '@SyliusShop/account/order/grid/field/total.html.twig')
->setLabel('sylius.ui.total')
->setPath('.')
->setSortable(true, 'total'),
TwigField::create('state', '@SyliusUi/grid/field/label.html.twig')
->setLabel('sylius.ui.state')
->setSortable(true)
->addOptions([
'vars' => [
'labels' => '@SyliusShop/account/order/label/state',
],
]),
)
->withItemActions(
Action::create('show', 'shop_show')
->setLabel('sylius.ui.show')
->setOptions([
'link' => [
'route' => 'sylius_shop_account_order_show',
'parameters' => [
'number' => 'resource.number',
],
],
]),
Action::create('pay', 'shop_pay')
->setLabel('sylius.ui.pay')
->setOptions([
'link' => [
'route' => 'sylius_shop_order_show',
'parameters' => [
'tokenValue' => 'resource.tokenValue',
],
],
]),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\ShopBundle\Grid\Account;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface OrderGridInterface
{
public const NAME = 'sylius_shop_account_order';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,59 @@
<?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\ShopBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\Field\DateTimeField;
use Sylius\Bundle\GridBundle\Builder\Field\Field;
use Sylius\Bundle\GridBundle\Builder\Field\StringField;
use Sylius\Bundle\GridBundle\Builder\Filter\Filter;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
use Sylius\Component\Grid\Attribute\AsGrid;
#[AsGrid(resourceClass: '%sylius.model.product.class%', name: self::NAME)]
final class ProductGrid implements ProductGridInterface
{
public function __invoke(GridBuilderInterface $gridBuilder): void
{
$gridBuilder
->setRepositoryMethod('createShopListQueryBuilder', [
'channel' => "expr:service('sylius.context.channel').getChannel()",
'taxon' => "expr:notFoundOnNull(service('sylius.repository.taxon').findOneBySlug(\$slug, service('sylius.context.locale').getLocaleCode()))",
'locale' => "expr:service('sylius.context.locale').getLocaleCode()",
'sorting' => "expr:service('request_stack').getCurrentRequest().query.all('sorting')",
'includeAllDescendants' => "expr:parameter('sylius_shop.product_grid.include_all_descendants')",
])
->orderBy('position', 'asc')
->setLimits([
9,
18,
27,
])
->withFields(
DateTimeField::create('createdAt')
->setSortable(true),
StringField::create('position')
->setSortable(true, 'productTaxon.position'),
StringField::create('name')
->setSortable(true, 'translation.name'),
Field::create('price', 'int')
->setSortable(true, 'channelPricing.price'),
)
->withFilters(
Filter::create('search', 'shop_string')
->setLabel(false)
->addOption('fields', ['translation.name'])
->addFormOption('type', 'contains'),
);
}
}

View file

@ -0,0 +1,24 @@
<?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\ShopBundle\Grid;
use Sylius\Bundle\GridBundle\Builder\GridBuilderInterface;
/** @experimental */
interface ProductGridInterface
{
public const NAME = 'sylius_shop_product';
public function __invoke(GridBuilderInterface $gridBuilder): void;
}

View file

@ -0,0 +1,30 @@
<?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 Symfony\Component\DependencyInjection\Loader\Configurator;
return static function (ContainerConfigurator $container) {
$services = $container->services();
$services->set('sylius_shop.grid.account.order', \Sylius\Bundle\ShopBundle\Grid\Account\OrderGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(\Sylius\Bundle\ShopBundle\Grid\Account\OrderGridInterface::class, 'sylius_shop.grid.account.order');
$services->set('sylius_shop.grid.product', \Sylius\Bundle\ShopBundle\Grid\ProductGrid::class)
->tag('sylius.invokable_grid')
;
$services->alias(\Sylius\Bundle\ShopBundle\Grid\ProductGridInterface::class, 'sylius_shop.grid.product');
};

View file

@ -33,7 +33,7 @@
"knplabs/knp-menu": "^3.5", "knplabs/knp-menu": "^3.5",
"knplabs/knp-menu-bundle": "^3.4", "knplabs/knp-menu-bundle": "^3.4",
"laminas/laminas-stdlib": "^3.19", "laminas/laminas-stdlib": "^3.19",
"sylius/grid-bundle": "^1.13", "sylius/grid-bundle": "^1.16@alpha",
"sylius/twig-extra": "^0.9", "sylius/twig-extra": "^0.9",
"symfony/config": "^6.4 || ^7.4", "symfony/config": "^6.4 || ^7.4",
"symfony/expression-language": "^6.4 || ^7.4", "symfony/expression-language": "^6.4 || ^7.4",

View file

@ -52,18 +52,6 @@
"dmore/chrome-mink-driver": { "dmore/chrome-mink-driver": {
"version": "2.7.0" "version": "2.7.0"
}, },
"doctrine/annotations": {
"version": "1.0",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"version": "1.0",
"ref": "a2759dd6123694c8d901d0ec80006e044c2e6457"
},
"files": [
"config/routes/annotations.yaml"
]
},
"doctrine/cache": { "doctrine/cache": {
"version": "1.10.2" "version": "1.10.2"
}, },
@ -200,9 +188,6 @@
"knplabs/knp-menu-bundle": { "knplabs/knp-menu-bundle": {
"version": "v3.0.0" "version": "v3.0.0"
}, },
"laminas/laminas-code": {
"version": "3.5.1"
},
"laminas/laminas-stdlib": { "laminas/laminas-stdlib": {
"version": "3.3.1" "version": "3.3.1"
}, },

View file

@ -0,0 +1,224 @@
<?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\Tests\Grid;
use PHPUnit\Framework\Attributes\DataProvider;
use Sylius\Bundle\GridBundle\Provider\ServiceGridProvider;
use Sylius\Component\Grid\Definition\Grid;
use Sylius\Component\Grid\Provider\ArrayGridProvider;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
/**
* This class is there to ensure that the yaml configuration of the grid is the same as the php configuration
*/
final class OverridenGridsTest extends KernelTestCase
{
#[DataProvider('dataProviderGrids')]
public function testPhpGridsHavingTheSameConfigurationAsYAMLGrids(string $gridName): void
{
$container = self::getContainer();
$arrayProvider = $container->get(ArrayGridProvider::class);
$serviceProvider = $container->get(ServiceGridProvider::class);
$serviceVersion = $serviceProvider->get($gridName);
$yamlVersion = $arrayProvider->get($gridName);
$this->prefillingRepository($yamlVersion);
$this->prefillingGridFields($yamlVersion);
$this->prefillingGridActions($yamlVersion);
$this->assertGridSame($yamlVersion, $serviceVersion);
}
public static function dataProviderGrids(): \Generator
{
$gridConfiguration = self::getContainer()->getParameter('sylius.grids_definitions');
self::assertNotEmpty($gridConfiguration, 'No grid configuration found');
foreach (array_keys($gridConfiguration) as $gridName) {
// This deprecated grid will not be migrated
if ($gridName === 'sylius_admin_address_log_entry') {
continue;
}
yield $gridName => [$gridName];
}
self::ensureKernelShutdown();
}
/**
* Prefilling the default values for datetime fields as they might not be set in YAML configuration
*/
private function prefillingGridFields(Grid $grid): void
{
foreach ($grid->getFields() as $field) {
// Prefilling the default values for datetime fields as they might not be set in YAML configuration
if ($field->getType() === 'datetime') {
$options = [
'format' => 'Y-m-d H:i:s',
'timezone' => null,
...$field->getOptions(),
];
$field->setOptions($options);
}
}
}
/**
* Prefilling the default values on Grid definitions.
* PHP Configuration add a default label, not set in YAML configuration
*/
private function prefillingGridActions(Grid $grid): void
{
if ($grid->hasActionGroup('main')) {
foreach ($grid->getActions('main') as $action) {
if ('create' === $action->getType() && null === $action->getLabel()) {
$action->setLabel('sylius.ui.create');
}
}
}
if ($grid->hasActionGroup('item')) {
foreach ($grid->getActions('item') as $action) {
if ('show' === $action->getType() && null === $action->getLabel()) {
$action->setLabel('sylius.ui.show');
}
if ('update' === $action->getType() && null === $action->getLabel()) {
$action->setLabel('sylius.ui.edit');
}
if ('delete' === $action->getType() && null === $action->getLabel()) {
$action->setLabel('sylius.ui.delete');
}
}
}
if ($grid->hasActionGroup('bulk')) {
foreach ($grid->getActions('bulk') as $action) {
if ('delete' === $action->getType() && null === $action->getLabel()) {
$action->setLabel('sylius.ui.delete');
}
}
}
}
private function prefillingRepository(Grid $grid): void
{
$config = $grid->getDriverConfiguration();
if (!array_key_exists('repository', $config)) {
return;
}
if (!array_key_exists('arguments', $config['repository'])) {
$config['repository']['arguments'] = [];
}
$grid->setDriverConfiguration($config);
}
public function assertGridSame(Grid $yamlGrid, Grid $serviceGrid): void
{
self::assertSame($yamlGrid->getCode(), $serviceGrid->getCode());
self::assertSame($yamlGrid->getDriver(), $serviceGrid->getDriver());
self::assertSameWithIgnoredOrder($yamlGrid->getDriverConfiguration(), $serviceGrid->getDriverConfiguration());
self::assertSame($yamlGrid->getProvider(), $serviceGrid->getProvider());
self::assertSame($yamlGrid->getSorting(), $serviceGrid->getSorting());
self::assertSame($yamlGrid->getLimits(), $serviceGrid->getLimits());
self::assertSame($yamlGrid->getSorting(), $serviceGrid->getSorting());
$serviceFields = $serviceGrid->getFields();
$this->assertSame(
array_keys($serviceGrid->getFields()),
array_keys($yamlGrid->getFields()),
'Field keys in grid do not match',
);
foreach ($yamlGrid->getFields() as $fieldName => $yamlField) {
$this->assertArrayHasKey($fieldName, $serviceFields);
$this->assertEquals($yamlField, $serviceFields[$fieldName]);
$serviceField = $serviceFields[$fieldName];
$this->assertSame($yamlField->getName(), $serviceField->getName(), 'Name of field '.$fieldName.' does not match');
$this->assertSame($yamlField->getType(), $serviceField->getType(), 'Type of field '.$fieldName.' does not match');
$this->assertSame($yamlField->getPath(), $serviceField->getPath(), 'Path of field '.$fieldName.' does not match');
$this->assertSame($yamlField->getLabel(), $serviceField->getLabel(), 'Label of field '.$fieldName.' does not match');
$this->assertSame($yamlField->isEnabled(), $serviceField->isEnabled(), 'Enabled state of field '.$fieldName.' does not match');
$this->assertSame($yamlField->isSortable(), $serviceField->isSortable(), 'Sortable state of field '.$fieldName.' does not match');
$this->assertSame($yamlField->getSortable(), $serviceField->getSortable(), 'Sortable path of field '.$fieldName.' does not match');
$this->assertSameWithIgnoredOrder($yamlField->getOptions(), $serviceField->getOptions(), 'Options of field '.$fieldName.' do not match');
$this->assertSame($yamlField->getPosition(), $serviceField->getPosition(), 'Position of field '.$fieldName.' does not match');
}
$serviceFilters = $serviceGrid->getFilters();
$this->assertSame(
array_keys($serviceGrid->getFilters()),
array_keys($yamlGrid->getFilters()),
'Filter keys in grid do not match',
);
foreach ($yamlGrid->getFilters() as $filterName => $yamlFilter) {
$this->assertArrayHasKey($filterName, $serviceFilters);
$serviceFilter = $serviceFilters[$filterName];
$this->assertSame($yamlFilter->isEnabled(), $serviceFilter->isEnabled(), 'Enabled state of filter '.$filterName. ' does not match');
$this->assertSame($yamlFilter->getName(), $serviceFilter->getName(), 'Name of filter '.$filterName. ' does not match');
$this->assertSame($yamlFilter->getType(), $serviceFilter->getType(), 'Type of filter '.$filterName. ' does not match');
$this->assertSame($yamlFilter->getLabel(), $serviceFilter->getLabel(), 'Label of filter '.$filterName. ' does not match');
$this->assertSame($yamlFilter->getTemplate(), $serviceFilter->getTemplate(), 'Template of filter '.$filterName. ' does not match');
$this->assertSameWithIgnoredOrder($yamlFilter->getOptions(), $serviceFilter->getOptions(), 'Options of filter '.$filterName. ' does not match');
$this->assertSameWithIgnoredOrder($yamlFilter->getFormOptions(), $serviceFilter->getFormOptions(), 'Form Options of filter '.$filterName. ' does not match');
$this->assertSame($yamlFilter->getCriteria(), $serviceFilter->getCriteria(), 'Criteria of filter '.$filterName. ' does not match');
$this->assertSame($yamlFilter->getPosition(), $serviceFilter->getPosition(), 'Position of filter '.$filterName. ' does not match');
}
// Assert actions are the same
$this->assertSame(
array_keys($serviceGrid->getActionGroups()),
array_keys($yamlGrid->getActionGroups()),
'Action keys in action groups do not match',
);
$serviceActions = $serviceGrid->getActionGroups();
foreach ($yamlGrid->getActionGroups() as $actionGroupName => $yamlActionGroup) {
$this->assertArrayHasKey($actionGroupName, $serviceActions);
$this->assertEquals($yamlActionGroup, $serviceActions[$actionGroupName]);
$serviceActionGroup = $serviceActions[$actionGroupName];
$this->assertSame(
array_keys($serviceActionGroup->getActions()),
array_keys($yamlActionGroup->getActions()),
'Action keys in action group '.$actionGroupName.' do not match',
);
foreach ($serviceActionGroup->getActions() as $name => $expectedAction) {
$actualAction = $yamlActionGroup->getAction($name);
$this->assertSame($expectedAction->getName(), $actualAction->getName(), 'Name of action '.$actionGroupName.' does not match');
$this->assertSame($expectedAction->getType(), $actualAction->getType(), 'Type of action '.$actionGroupName.' does not match');
$this->assertSame($expectedAction->getLabel(), $actualAction->getLabel(), 'Label of action '.$actionGroupName.' does not match');
$this->assertSame($expectedAction->isEnabled(), $actualAction->isEnabled(), 'Enabled state of action '.$actionGroupName.' does not match');
$this->assertSame($expectedAction->getTemplate(), $actualAction->getTemplate(), 'Template of action '.$actionGroupName.' does not match');
$this->assertSame($expectedAction->getIcon(), $actualAction->getIcon(), 'Icon of action '.$actionGroupName.' does not match');
$this->assertSameWithIgnoredOrder($expectedAction->getOptions(), $actualAction->getOptions(), 'Options of action '.$actionGroupName.' do not match');
$this->assertSame($expectedAction->getPosition(), $actualAction->getPosition(), 'Position of action '.$actionGroupName.' does not match');
}
}
}
private function assertSameWithIgnoredOrder(array $expected, array $actual): void
{
ksort($expected);
ksort($actual);
$this->assertSame($expected, $actual);
}
}