Skip to content

Commit de6e557

Browse files
committed
Create initial entities and renderers
1 parent 5aa87d4 commit de6e557

26 files changed

+620
-108
lines changed

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024 Setono
3+
Copyright (c) 2025 Setono
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

composer.json

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
],
1010
"require": {
1111
"php": ">=8.1",
12+
"setono/composite-compiler-pass": "^1.2",
1213
"sylius/core-bundle": "^1.0",
1314
"symfony/config": "^5.4 || ^6.4 || ^7.0",
1415
"symfony/dependency-injection": "^5.4 || ^6.4 || ^7.0",
15-
"symfony/http-kernel": "^5.4 || ^6.4 || ^7.0"
16+
"symfony/http-kernel": "^5.4 || ^6.4 || ^7.0",
17+
"twig/twig": "^3.0"
1618
},
1719
"require-dev": {
1820
"api-platform/core": "^2.7.16",
@@ -22,12 +24,11 @@
2224
"infection/infection": "^0.27.11",
2325
"jms/serializer-bundle": "^4.2",
2426
"lexik/jwt-authentication-bundle": "^2.17",
25-
"matthiasnoback/symfony-config-test": "^4.3 || ^5.1",
26-
"matthiasnoback/symfony-dependency-injection-test": "^4.3 || ^5.1",
27+
"phpspec/prophecy-phpunit": "^2.3",
2728
"phpunit/phpunit": "^9.6.20",
2829
"psalm/plugin-phpunit": "^0.18.4",
29-
"setono/code-quality-pack": "^2.8.1",
30-
"shipmonk/composer-dependency-analyser": "^1.6",
30+
"setono/code-quality-pack": "^2.9",
31+
"shipmonk/composer-dependency-analyser": "^1.8.2",
3132
"sylius/sylius": "~1.12.19",
3233
"symfony/debug-bundle": "^5.4 || ^6.4 || ^7.0",
3334
"symfony/dotenv": "^5.4 || ^6.4 || ^7.0",

src/DependencyInjection/Configuration.php

-8
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,6 @@ public function getConfigTreeBuilder(): TreeBuilder
1717
/** @var ArrayNodeDefinition $rootNode */
1818
$rootNode = $treeBuilder->getRootNode();
1919

20-
$rootNode
21-
->children()
22-
->scalarNode('option')
23-
->info('This is an example configuration option')
24-
->isRequired()
25-
->cannotBeEmpty()
26-
;
27-
2820
return $treeBuilder;
2921
}
3022
}

src/DependencyInjection/SetonoSyliusNavigationExtension.php

-4
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,10 @@ public function load(array $configs, ContainerBuilder $container): void
1515
{
1616
/**
1717
* @psalm-suppress PossiblyNullArgument
18-
*
19-
* @var array{option: scalar} $config
2018
*/
2119
$config = $this->processConfiguration($this->getConfiguration([], $container), $configs);
2220
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
2321

24-
$container->setParameter('setono_sylius_navigation.option', $config['option']);
25-
2622
$loader->load('services.xml');
2723
}
2824
}

src/Model/Navigation.php

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusNavigationPlugin\Model;
6+
7+
use Doctrine\Common\Collections\ArrayCollection;
8+
use Doctrine\Common\Collections\Collection;
9+
use Sylius\Component\Channel\Model\ChannelInterface;
10+
use Sylius\Resource\Model\TimestampableTrait;
11+
use Sylius\Resource\Model\ToggleableTrait;
12+
13+
class Navigation implements NavigationInterface
14+
{
15+
use TimestampableTrait;
16+
use ToggleableTrait;
17+
18+
protected ?int $id = null;
19+
20+
protected ?string $code = null;
21+
22+
protected ?NavigationItemInterface $rootItem = null;
23+
24+
protected ?int $maxDepth = null;
25+
26+
/** @var Collection<array-key, ChannelInterface> */
27+
protected Collection $channels;
28+
29+
public function __construct()
30+
{
31+
$this->channels = new ArrayCollection();
32+
}
33+
34+
public function getId(): ?int
35+
{
36+
return $this->id;
37+
}
38+
39+
public function getCode(): ?string
40+
{
41+
return $this->code;
42+
}
43+
44+
public function setCode(?string $code): void
45+
{
46+
$this->code = $code;
47+
}
48+
49+
public function getRootItem(): ?NavigationItemInterface
50+
{
51+
return $this->rootItem;
52+
}
53+
54+
public function setRootItem(?NavigationItemInterface $rootItem): void
55+
{
56+
$this->rootItem = $rootItem;
57+
}
58+
59+
public function getMaxDepth(): ?int
60+
{
61+
return $this->maxDepth;
62+
}
63+
64+
public function setMaxDepth(?int $maxDepth): void
65+
{
66+
$this->maxDepth = $maxDepth;
67+
}
68+
69+
public function getChannels(): Collection
70+
{
71+
return $this->channels;
72+
}
73+
74+
public function addChannel(ChannelInterface $channel): void
75+
{
76+
if (!$this->hasChannel($channel)) {
77+
$this->channels->add($channel);
78+
}
79+
}
80+
81+
public function removeChannel(ChannelInterface $channel): void
82+
{
83+
if ($this->hasChannel($channel)) {
84+
$this->channels->removeElement($channel);
85+
}
86+
}
87+
88+
public function hasChannel(ChannelInterface $channel): bool
89+
{
90+
return $this->channels->contains($channel);
91+
}
92+
}

src/Model/NavigationInterface.php

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusNavigationPlugin\Model;
6+
7+
use Sylius\Component\Channel\Model\ChannelsAwareInterface;
8+
use Sylius\Resource\Model\CodeAwareInterface;
9+
use Sylius\Resource\Model\ResourceInterface;
10+
use Sylius\Resource\Model\TimestampableInterface;
11+
use Sylius\Resource\Model\ToggleableInterface;
12+
13+
interface NavigationInterface extends
14+
ChannelsAwareInterface,
15+
CodeAwareInterface,
16+
ResourceInterface,
17+
TimestampableInterface,
18+
ToggleableInterface
19+
{
20+
public function getRootItem(): ?NavigationItemInterface;
21+
22+
public function setRootItem(?NavigationItemInterface $rootItem): void;
23+
24+
public function getMaxDepth(): ?int;
25+
26+
public function setMaxDepth(?int $maxDepth): void;
27+
}

src/Model/NavigationItemInterface.php

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusNavigationPlugin\Model;
6+
7+
use Doctrine\Common\Collections\Collection;
8+
use Sylius\Component\Channel\Model\ChannelsAwareInterface;
9+
use Sylius\Component\Core\Model\PositionAwareInterface;
10+
use Sylius\Resource\Model\ResourceInterface;
11+
use Sylius\Resource\Model\TimestampableInterface;
12+
use Sylius\Resource\Model\ToggleableInterface;
13+
use Sylius\Resource\Model\TranslatableInterface;
14+
15+
interface NavigationItemInterface extends
16+
ChannelsAwareInterface,
17+
PositionAwareInterface,
18+
ResourceInterface,
19+
TimestampableInterface,
20+
ToggleableInterface,
21+
TranslatableInterface
22+
{
23+
public function getNavigation(): ?NavigationInterface;
24+
25+
public function getLabel(): ?string;
26+
27+
public function setLabel(?string $label): void;
28+
29+
public function getParent(): ?self;
30+
31+
/**
32+
* @return Collection<int, NavigationItemInterface>
33+
*/
34+
public function getChildren(): Collection;
35+
36+
public function hasChildren(): bool;
37+
38+
public function addChild(self $item): void;
39+
40+
public function removeChild(self $item): void;
41+
42+
public function hasChild(self $item): bool;
43+
44+
public function getLevel(): int;
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusNavigationPlugin\Renderer\Item;
6+
7+
use Psr\Log\LoggerAwareInterface;
8+
use Psr\Log\LoggerInterface;
9+
use Psr\Log\NullLogger;
10+
use Setono\CompositeCompilerPass\CompositeService;
11+
use Setono\SyliusNavigationPlugin\Model\NavigationItemInterface;
12+
13+
/**
14+
* @extends CompositeService<NavigationItemRendererInterface>
15+
*/
16+
final class CompositeNavigationItemRenderer extends CompositeService implements NavigationItemRendererInterface, LoggerAwareInterface
17+
{
18+
private LoggerInterface $logger;
19+
20+
public function __construct()
21+
{
22+
$this->logger = new NullLogger();
23+
}
24+
25+
public function render(NavigationItemInterface $item): string
26+
{
27+
foreach ($this->services as $service) {
28+
if ($service->supports($item)) {
29+
return $service->render($item);
30+
}
31+
}
32+
33+
$this->logger->error('Could not find a navigation item renderer for item "{item}"', [
34+
'item' => $item::class,
35+
]);
36+
37+
return '';
38+
}
39+
40+
public function supports(NavigationItemInterface $item): bool
41+
{
42+
foreach ($this->services as $service) {
43+
if ($service->supports($item)) {
44+
return true;
45+
}
46+
}
47+
48+
return false;
49+
}
50+
51+
public function setLogger(LoggerInterface $logger): void
52+
{
53+
$this->logger = $logger;
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusNavigationPlugin\Renderer\Item;
6+
7+
use Setono\SyliusNavigationPlugin\Model\NavigationItemInterface;
8+
use Twig\Environment;
9+
10+
final class DefaultNavigationItemRenderer implements NavigationItemRendererInterface
11+
{
12+
public function __construct(private readonly Environment $twig)
13+
{
14+
}
15+
16+
public function render(NavigationItemInterface $item): string
17+
{
18+
return $this->twig->render('@SetonoSyliusNavigationPlugin/navigation/item/default.html.twig', [
19+
'item' => $item,
20+
]);
21+
}
22+
23+
public function supports(NavigationItemInterface $item): bool
24+
{
25+
return true;
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusNavigationPlugin\Renderer\Item;
6+
7+
use Setono\SyliusNavigationPlugin\Model\NavigationItemInterface;
8+
9+
interface NavigationItemRendererInterface
10+
{
11+
public function render(NavigationItemInterface $item): string;
12+
13+
public function supports(NavigationItemInterface $item): bool;
14+
}

src/Renderer/NavigationRenderer.php

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Setono\SyliusNavigationPlugin\Renderer;
6+
7+
use Psr\Log\LoggerAwareInterface;
8+
use Psr\Log\LoggerInterface;
9+
use Psr\Log\NullLogger;
10+
use Setono\SyliusNavigationPlugin\Model\NavigationInterface;
11+
use Setono\SyliusNavigationPlugin\Repository\NavigationRepositoryInterface;
12+
use Sylius\Component\Channel\Context\ChannelContextInterface;
13+
use Sylius\Component\Channel\Model\ChannelInterface;
14+
use Sylius\Component\Locale\Context\LocaleContextInterface;
15+
use Twig\Environment;
16+
17+
// todo cache this
18+
final class NavigationRenderer implements NavigationRendererInterface, LoggerAwareInterface
19+
{
20+
private LoggerInterface $logger;
21+
22+
public function __construct(
23+
private readonly NavigationRepositoryInterface $navigationRepository,
24+
private readonly ChannelContextInterface $channelContext,
25+
private readonly LocaleContextInterface $localeContext,
26+
private readonly Environment $twig,
27+
private readonly string $template = '@SetonoSyliusNavigationPlugin/navigation/navigation.html.twig',
28+
) {
29+
$this->logger = new NullLogger();
30+
}
31+
32+
public function render(
33+
NavigationInterface|string $navigation,
34+
ChannelInterface $channel = null,
35+
string $localeCode = null,
36+
): string {
37+
$channel = $channel ?? $this->channelContext->getChannel();
38+
$localeCode = $localeCode ?? $this->localeContext->getLocaleCode();
39+
40+
if (is_string($navigation)) {
41+
$navigation = $this->navigationRepository->findOneEnabledByCode($navigation, $channel);
42+
if (null === $navigation) {
43+
$this->logger->error('Could not find navigation with code {code} on channel "{channel}"', [
44+
'code' => $navigation,
45+
'channel' => $channel->getCode(),
46+
]);
47+
48+
return '';
49+
}
50+
}
51+
52+
return $this->twig->render($this->template, [
53+
'navigation' => $navigation,
54+
'channel' => $channel,
55+
'localeCode' => $localeCode,
56+
]);
57+
}
58+
59+
public function setLogger(LoggerInterface $logger): void
60+
{
61+
$this->logger = $logger;
62+
}
63+
}

0 commit comments

Comments
 (0)