Skip to content

Commit 3a9b8d8

Browse files
authored
Added extension point to resolve preview URL (#1693)
* Added extension point to resolve preview URL * Add unit tests for VersionPreviewUrlResolver * Add unit tests for SystemVersionPreviewUrlSubscriber * [PHPStan] Resolved phpstan issues * Applied code review suggestions
1 parent f0a8d30 commit 3a9b8d8

File tree

17 files changed

+634
-31
lines changed

17 files changed

+634
-31
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,6 @@ parameters:
198198
count: 1
199199
path: src/bundle/Controller/ContentController.php
200200

201-
-
202-
message: '#^Parameter \#1 \$location of method Ibexa\\AdminUi\\Siteaccess\\SiteaccessResolverInterface\:\:getSiteAccessesListForLocation\(\) expects Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\Location, Ibexa\\Contracts\\Core\\Repository\\Values\\Content\\Location\|false given\.$#'
203-
identifier: argument.type
204-
count: 1
205-
path: src/bundle/Controller/ContentController.php
206-
207201
-
208202
message: '#^Parameter \#1 \$locationId of method Ibexa\\Contracts\\Core\\Repository\\LocationService\:\:loadLocation\(\) expects int, int\|null given\.$#'
209203
identifier: argument.type

src/bundle/Controller/ContentController.php

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use Ibexa\AdminUi\Form\Factory\FormFactory;
1919
use Ibexa\AdminUi\Form\SubmitHandler;
2020
use Ibexa\AdminUi\Form\Type\Content\Translation\MainTranslationUpdateType;
21-
use Ibexa\AdminUi\Form\Type\Preview\SiteAccessChoiceType;
21+
use Ibexa\AdminUi\Form\Type\Preview\VersionPreviewUrlChoiceType;
2222
use Ibexa\AdminUi\Permission\LookupLimitationsTransformer;
2323
use Ibexa\AdminUi\Siteaccess\SiteAccessNameGeneratorInterface;
2424
use Ibexa\AdminUi\Siteaccess\SiteaccessResolverInterface;
@@ -28,10 +28,12 @@
2828
use Ibexa\Contracts\AdminUi\Event\ContentEditEvent;
2929
use Ibexa\Contracts\AdminUi\Event\ContentProxyCreateEvent;
3030
use Ibexa\Contracts\AdminUi\Notification\TranslatableNotificationHandlerInterface;
31+
use Ibexa\Contracts\AdminUi\PreviewUrlResolver\VersionPreviewUrlResolverInterface;
3132
use Ibexa\Contracts\Core\Limitation\Target;
3233
use Ibexa\Contracts\Core\Repository\ContentService;
3334
use Ibexa\Contracts\Core\Repository\Exceptions as ApiException;
3435
use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException;
36+
use Ibexa\Contracts\Core\Repository\LanguageService;
3537
use Ibexa\Contracts\Core\Repository\LocationService;
3638
use Ibexa\Contracts\Core\Repository\PermissionResolver;
3739
use Ibexa\Contracts\Core\Repository\UserService;
@@ -42,6 +44,7 @@
4244
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
4345
use Ibexa\Core\Base\Exceptions\BadStateException;
4446
use Ibexa\Core\Helper\TranslationHelper;
47+
use Ibexa\Core\MVC\Symfony\SiteAccess\SiteAccessServiceInterface;
4548
use JMS\TranslationBundle\Annotation\Desc;
4649
use Symfony\Component\Form\FormFactoryInterface;
4750
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -96,6 +99,12 @@ class ContentController extends Controller
9699

97100
private FormFactoryInterface $baseFormFactory;
98101

102+
private VersionPreviewUrlResolverInterface $previewUrlResolver;
103+
104+
private LanguageService $languageService;
105+
106+
private SiteAccessServiceInterface $siteAccessService;
107+
99108
public function __construct(
100109
TranslatableNotificationHandlerInterface $notificationHandler,
101110
ContentService $contentService,
@@ -111,7 +120,10 @@ public function __construct(
111120
ConfigResolverInterface $configResolver,
112121
SiteAccessNameGeneratorInterface $siteAccessNameGenerator,
113122
EventDispatcherInterface $eventDispatcher,
114-
FormFactoryInterface $baseFormFactory
123+
FormFactoryInterface $baseFormFactory,
124+
VersionPreviewUrlResolverInterface $previewUrlResolver,
125+
LanguageService $languageService,
126+
SiteAccessServiceInterface $siteAccessService
115127
) {
116128
$this->notificationHandler = $notificationHandler;
117129
$this->contentService = $contentService;
@@ -128,6 +140,9 @@ public function __construct(
128140
$this->siteAccessNameGenerator = $siteAccessNameGenerator;
129141
$this->eventDispatcher = $eventDispatcher;
130142
$this->baseFormFactory = $baseFormFactory;
143+
$this->previewUrlResolver = $previewUrlResolver;
144+
$this->languageService = $languageService;
145+
$this->siteAccessService = $siteAccessService;
131146
}
132147

133148
/**
@@ -386,12 +401,11 @@ public function previewAction(
386401
$versionNo = null;
387402
}
388403

389-
if (null === $location) {
404+
if (!$location instanceof Location) {
390405
$location = $this->locationService->loadLocation($content->contentInfo->mainLocationId);
391406
}
392407

393408
$siteAccesses = $this->siteaccessResolver->getSiteAccessesListForLocation($location, $versionNo, $languageCode);
394-
395409
if (empty($siteAccesses)) {
396410
throw new BadStateException(
397411
'siteaccess',
@@ -404,30 +418,28 @@ public function previewAction(
404418
$siteAccessesList[$siteAccess->name] = $this->siteAccessNameGenerator->generate($siteAccess);
405419
}
406420

407-
$preselectedSiteAccess = $request->query->get('preselectedSiteAccess', reset($siteAccessesList));
408-
409-
if (!array_key_exists($preselectedSiteAccess, $siteAccessesList)) {
410-
$preselectedSiteAccess = reset($siteAccessesList);
421+
$preselectedSiteAccessName = $request->query->get('preselectedSiteAccessName', reset($siteAccessesList));
422+
if (!array_key_exists($preselectedSiteAccessName, $siteAccessesList)) {
423+
$preselectedSiteAccessName = reset($siteAccessesList);
411424
}
412425

413-
$urlValue = $this->generateUrl(
414-
'ibexa.version.preview',
415-
[
416-
'contentId' => $content->id,
417-
'versionNo' => $versionNo ?? $content->getVersionInfo()->versionNo,
418-
'language' => $languageCode,
419-
'siteAccessName' => $preselectedSiteAccess,
420-
]
426+
$versionInfo = $this->contentService->loadVersionInfo($content->getContentInfo(), $versionNo);
427+
$language = $this->languageService->loadLanguage($languageCode);
428+
429+
$previewUrl = $this->previewUrlResolver->resolveUrl(
430+
$versionInfo,
431+
$location,
432+
$language,
433+
$this->siteAccessService->get($preselectedSiteAccessName)
421434
);
422435

423436
$siteAccessSelector = $this->baseFormFactory->create(
424-
SiteAccessChoiceType::class,
425-
$urlValue,
437+
VersionPreviewUrlChoiceType::class,
438+
$previewUrl,
426439
[
427440
'location' => $location,
428-
'content' => $content,
429-
'versionNo' => $versionNo ?? $content->getVersionInfo()->versionNo,
430-
'languageCode' => $languageCode,
441+
'version_info' => $versionInfo,
442+
'language' => $language,
431443
]
432444
);
433445

@@ -438,8 +450,9 @@ public function previewAction(
438450
'siteaccesses' => $siteAccessesList,
439451
'site_access_form' => $siteAccessSelector->createView(),
440452
'version_no' => $versionNo ?? $content->getVersionInfo()->versionNo,
441-
'preselected_site_access' => $preselectedSiteAccess,
453+
'preselected_site_access' => $preselectedSiteAccessName,
442454
'referrer' => $referrer ?? 'content_draft_edit',
455+
'preview_url' => $previewUrl,
443456
]);
444457
}
445458

src/bundle/Resources/config/services.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ imports:
2626
- { resource: services/user_settings.yaml }
2727
- { resource: services/rest.yaml }
2828
- { resource: services/permissions.yaml }
29+
- { resource: services/preview.yaml }
2930
- { resource: services/forms.yaml }
3031
- { resource: services/strategies.yaml }
3132
- { resource: services/query_types.yaml }

src/bundle/Resources/config/services/forms.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,4 +424,9 @@ services:
424424
$siteAccessResolver: '@Ibexa\AdminUi\Siteaccess\NonAdminSiteaccessResolver'
425425
$siteAccessNameGenerator: '@Ibexa\AdminUi\Siteaccess\SiteAccessNameGenerator'
426426

427+
Ibexa\AdminUi\Form\Type\Preview\VersionPreviewUrlChoiceType:
428+
arguments:
429+
$siteAccessResolver: '@Ibexa\AdminUi\Siteaccess\NonAdminSiteaccessResolver'
430+
$siteAccessNameGenerator: '@Ibexa\AdminUi\Siteaccess\SiteAccessNameGenerator'
431+
427432
Ibexa\AdminUi\Form\Type\LanguageSwitchType: ~
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
services:
2+
_defaults:
3+
autowire: true
4+
autoconfigure: true
5+
public: false
6+
7+
Ibexa\Contracts\AdminUi\PreviewUrlResolver\VersionPreviewUrlResolverInterface:
8+
alias: Ibexa\AdminUi\PreviewUrlResolver\VersionPreviewUrlResolver
9+
10+
Ibexa\AdminUi\PreviewUrlResolver\VersionPreviewUrlResolver: ~

src/bundle/Resources/views/themes/admin/content/content_preview.html.twig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@
6565
{% block content %}
6666
<div class="ibexa-preview">
6767
<div class="ibexa-preview__iframe ibexa-preview__iframe--desktop">
68-
<iframe src="{{ url('ibexa.version.preview', {
69-
'contentId': content.id, 'versionNo': version_no, 'language': language_code, 'siteAccessName': preselected_site_access
70-
}) }}" frameborder="0"></iframe>
68+
<iframe src="{{ preview_url }}" frameborder="0"></iframe>
7169
</div>
7270
</div>
7371
{% endblock %}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Contracts\AdminUi\Event;
10+
11+
use Ibexa\Contracts\Core\Repository\Values\Content\Language;
12+
use Ibexa\Contracts\Core\Repository\Values\Content\Location;
13+
use Ibexa\Contracts\Core\Repository\Values\Content\VersionInfo;
14+
use Ibexa\Core\MVC\Symfony\SiteAccess;
15+
use Symfony\Contracts\EventDispatcher\Event;
16+
17+
final class ResolveVersionPreviewUrlEvent extends Event
18+
{
19+
private VersionInfo $versionInfo;
20+
21+
private Language $language;
22+
23+
private Location $location;
24+
25+
private SiteAccess $siteAccess;
26+
27+
private ?string $previewUrl = null;
28+
29+
public function __construct(
30+
VersionInfo $versionInfo,
31+
Language $language,
32+
Location $location,
33+
SiteAccess $siteAccess
34+
) {
35+
$this->versionInfo = $versionInfo;
36+
$this->language = $language;
37+
$this->location = $location;
38+
$this->siteAccess = $siteAccess;
39+
}
40+
41+
public function getVersionInfo(): VersionInfo
42+
{
43+
return $this->versionInfo;
44+
}
45+
46+
public function getLanguage(): Language
47+
{
48+
return $this->language;
49+
}
50+
51+
public function getLocation(): Location
52+
{
53+
return $this->location;
54+
}
55+
56+
public function getSiteAccess(): SiteAccess
57+
{
58+
return $this->siteAccess;
59+
}
60+
61+
public function getPreviewUrl(): ?string
62+
{
63+
return $this->previewUrl;
64+
}
65+
66+
public function setPreviewUrl(?string $previewUrl): void
67+
{
68+
$this->previewUrl = $previewUrl;
69+
}
70+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Contracts\AdminUi\Exception;
10+
11+
use Ibexa\Contracts\Core\Repository\Exceptions\Exception as RepositoryException;
12+
use RuntimeException;
13+
14+
final class UnresolvedPreviewUrlException extends RuntimeException implements RepositoryException
15+
{
16+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Contracts\AdminUi\PreviewUrlResolver;
10+
11+
use Ibexa\Contracts\Core\Repository\Values\Content\Language;
12+
use Ibexa\Contracts\Core\Repository\Values\Content\Location;
13+
use Ibexa\Contracts\Core\Repository\Values\Content\VersionInfo;
14+
use Ibexa\Core\MVC\Symfony\SiteAccess;
15+
16+
interface VersionPreviewUrlResolverInterface
17+
{
18+
public function resolveUrl(
19+
VersionInfo $versionInfo,
20+
Location $location,
21+
Language $language,
22+
SiteAccess $siteAccess
23+
): string;
24+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\AdminUi\EventListener;
10+
11+
use Ibexa\Contracts\AdminUi\Event\ResolveVersionPreviewUrlEvent;
12+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
13+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
14+
15+
final class SystemVersionPreviewUrlSubscriber implements EventSubscriberInterface
16+
{
17+
private UrlGeneratorInterface $urlGenerator;
18+
19+
public function __construct(UrlGeneratorInterface $urlGenerator)
20+
{
21+
$this->urlGenerator = $urlGenerator;
22+
}
23+
24+
public static function getSubscribedEvents(): array
25+
{
26+
return [
27+
ResolveVersionPreviewUrlEvent::class => ['onResolveVersionPreviewUrl', -100],
28+
];
29+
}
30+
31+
public function onResolveVersionPreviewUrl(ResolveVersionPreviewUrlEvent $event): void
32+
{
33+
if ($event->getPreviewUrl() !== null) {
34+
// Do not override already set preview URL
35+
return;
36+
}
37+
38+
$previewUrl = $this->urlGenerator->generate(
39+
'ibexa.version.preview',
40+
[
41+
'contentId' => $event->getVersionInfo()->getContentInfo()->getId(),
42+
'versionNo' => $event->getVersionInfo()->getVersionNo(),
43+
'language' => $event->getLanguage()->getLanguageCode(),
44+
'siteAccessName' => $event->getSiteAccess()->name,
45+
],
46+
);
47+
48+
$event->setPreviewUrl($previewUrl);
49+
}
50+
}

0 commit comments

Comments
 (0)