Skip to content

Commit

Permalink
Add redirect path Twig extension
Browse files Browse the repository at this point in the history
  • Loading branch information
loic425 committed Oct 2, 2024
1 parent 945e731 commit f56bec3
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 9 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"laminas/laminas-stdlib": "^3.18",
"pagerfanta/doctrine-orm-adapter": "^4.6",
"pagerfanta/twig": "^4.6",
"sylius/grid-bundle": "^1.13@alpha",
"sylius/resource-bundle": "^1.11 || ^1.12@alpha",
"sylius/grid-bundle": "^1.13@beta",
"sylius/resource-bundle": "^1.12@beta",
"symfony/asset": "^6.4 || ^7.0",
"symfony/config": "^6.4 || ^7.0",
"symfony/dependency-injection": "^6.4 || ^7.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@

{% set configuration = hookable_metadata.context.configuration %}

{#{% set index_url = sylius_generate_redirect_path(app.request.headers.get('referer')|default(path(#}
{# configuration.vars.index.route.name|default(configuration.getRouteName('index')),#}
{# configuration.vars.index.route.parameters|default(configuration.vars.route.parameters|default({}))#}
{#))) %}#}

{% set index_url = path(
{% set index_url = sylius_generate_redirect_path(app.request.headers.get('referer')|default(path(
configuration.vars.index.route.name|default(configuration.getRouteName('index')),
configuration.vars.index.route.parameters|default(configuration.vars.route.parameters|default({}))
) %}
))) %}

{{ button.cancel(sylius_test_form_attribute('cancel-changes-button')|merge({ text: 'sylius.ui.cancel'|trans, url: index_url, class: 'btn' })) }}
9 changes: 9 additions & 0 deletions src/TwigExtra/config/services/twig/extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Sylius\TwigExtra\Twig\Extension\MergeRecursiveExtension;
use Sylius\TwigExtra\Twig\Extension\RedirectPathExtension;
use Sylius\TwigExtra\Twig\Extension\RouteExistsExtension;
use Sylius\TwigExtra\Twig\Extension\SortByExtension;
use Sylius\TwigExtra\Twig\Extension\TestFormAttributeExtension;
Expand Down Expand Up @@ -52,4 +53,12 @@
])
->tag(name: 'twig.extension')
;

$services->set('sylius_twig_extra.twig.extension.redirect_path', RedirectPathExtension::class)
->args([
service('sylius.grid.filter_storage'),
service('router'),
])
->tag(name: 'twig.extension')
;
};
69 changes: 69 additions & 0 deletions src/TwigExtra/src/Twig/Extension/RedirectPathExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?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\TwigExtra\Twig\Extension;

use Sylius\Bundle\GridBundle\Storage\FilterStorageInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

final class RedirectPathExtension extends AbstractExtension
{
private const NUMBER_OF_ROUTE_PROPERTIES = 3;

public function __construct(
private readonly FilterStorageInterface $filterStorage,
private readonly RouterInterface $router,
) {
}

public function getFunctions(): array
{
return [
new TwigFunction('sylius_generate_redirect_path', [$this, 'generateRedirectPath']),
];
}

public function generateRedirectPath(?string $path): ?string
{
if (null === $path) {
return null;
}

$request = Request::create($path);

try {
$routeInfo = $this->router->match($request->getPathInfo());
} catch (\Throwable) {
return $path;
}

if ([] !== $request->query->all() || $this->hasAdditionalParameters($routeInfo)) {
return $path;
}

$route = $routeInfo['_route'];

return $this->router->generate($route, $this->filterStorage->all());
}

/**
* @param mixed[] $routeInfo
*/
private function hasAdditionalParameters(array $routeInfo): bool
{
return count($routeInfo) > self::NUMBER_OF_ROUTE_PROPERTIES;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?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\TwigExtra\Functional\Twig\Extension;

use Sylius\TwigExtra\Twig\Extension\RedirectPathExtension;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Request;

final class RedirectPathExtensionTest extends KernelTestCase
{
private RedirectPathExtension $redirectPathExtension;

protected function setUp(): void
{
$container = self::getContainer();

$session = $container->get('session.factory')->createSession();
$request = new Request();
$request->setSession($session);
$container->get('request_stack')->push($request);

$this->redirectPathExtension = $container->get('sylius_twig_extra.twig.extension.redirect_path');
$container->get('sylius.grid.filter_storage')->set(['criteria' => ['enabled' => true]]);
}

public function testItReturnsRedirectPathWithFiltersFromStorageApplied(): void
{
// Note, it requires an existing route path.
$redirectPath = $this->redirectPathExtension->generateRedirectPath('/admin/books');

$this->assertSame('/admin/books?criteria%5Benabled%5D=1', $redirectPath);
}

public function testItReturnsGivenPathIfRouteHasSomeMoreConfiguration(): void
{
$redirectPath = $this->redirectPathExtension->generateRedirectPath('/admin/ajax/products/search');

$this->assertSame('/admin/ajax/products/search', $redirectPath);
}

public function testItReturnsGivenPathIfRouteIsNotMatched(): void
{
$redirectPath = $this->redirectPathExtension->generateRedirectPath('/admin/invalid-path');

$this->assertSame('/admin/invalid-path', $redirectPath);
}

public function testItReturnsNullIfThePathIsNullAsWell(): void
{
$redirectPath = $this->redirectPathExtension->generateRedirectPath(null);

$this->assertNull($redirectPath);
}
}
104 changes: 104 additions & 0 deletions src/TwigExtra/tests/Unit/Symfony/Session/SessionFilterStorageTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?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\TwigExtra\Unit\Symfony\Session;

use PHPUnit\Framework\TestCase;
use Sylius\TwigExtra\Storage\FiltersStorageInterface;
use Sylius\TwigExtra\Symfony\Session\Storage\SessionFiltersStorage;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;

final class SessionFilterStorageTest extends TestCase
{
public function testItImplementsFilterStorageInterface(): void
{
$this->assertInstanceOf(FiltersStorageInterface::class, new SessionFiltersStorage(new RequestStack()));
}

public function testItSetsFiltersInASession(): void
{
$filters = [
'filter' => 'value',
];

$requestStack = new RequestStack();
$request = new Request();
$session = new Session(new MockArraySessionStorage());

$request->setSession($session);
$requestStack->push($request);

$filterStorage = new SessionFiltersStorage($requestStack);
$filterStorage->set($filters);

$this->assertEquals($filters, $session->get('filters'));
}

public function testItReturnsAllFiltersFromASession(): void
{
$filters = [
'filter' => 'value',
];

$requestStack = new RequestStack();
$request = new Request();
$session = new Session(new MockArraySessionStorage());

$session->set('filters', $filters);
$request->setSession($session);
$requestStack->push($request);

$filterStorage = new SessionFiltersStorage($requestStack);

$this->assertEquals($filters, $filterStorage->all());
}

public function testItReturnsTrueIfFiltersAreSet(): void
{
$filters = [
'filter' => 'value',
];

$requestStack = new RequestStack();
$request = new Request();
$session = new Session(new MockArraySessionStorage());

$session->set('filters', $filters);
$request->setSession($session);
$requestStack->push($request);

$filterStorage = new SessionFiltersStorage($requestStack);

$this->assertTrue($filterStorage->hasFilters());
}

public function testItReturnsFalseIfFiltersAreSet(): void
{
$filters = [];

$requestStack = new RequestStack();
$request = new Request();
$session = new Session(new MockArraySessionStorage());

$session->set('filters', $filters);
$request->setSession($session);
$requestStack->push($request);

$filterStorage = new SessionFiltersStorage($requestStack);

$this->assertFalse($filterStorage->hasFilters());
}
}

0 comments on commit f56bec3

Please sign in to comment.