Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions phpstan-baseline-7.4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,6 @@ parameters:
count: 1
path: src/lib/MVC/Symfony/Matcher/ContentBased/UrlAlias.php

-
message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\FieldValue\\Converter\\DateAndTimeConverter\:\:getDateIntervalFromXML\(\) should return DateInterval but returns DateInterval\|false\.$#'
identifier: return.type
count: 1
path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/DateAndTimeConverter.php

-
message: '#^Cannot access property \$ownerDocument on DOMElement\|false\.$#'
identifier: property.nonObject
Expand Down
6 changes: 0 additions & 6 deletions phpstan-baseline-doctrine-persistence-v3.neon
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
parameters:
ignoreErrors:
-
message: '#^Call to function method_exists\(\) with Doctrine\\ORM\\EntityManagerInterface and ''isUninitializedObje…'' will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType
count: 1
path: src/lib/Persistence/Doctrine/SiteAccessAwareEntityManager.php

-
message: '#^Method Doctrine\\Persistence\\ObjectManager\:\:clear\(\) invoked with 1 parameter, 0 required\.$#'
identifier: arguments.count
Expand Down
6 changes: 6 additions & 0 deletions phpstan-baseline-lte-8.1.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
parameters:
ignoreErrors:
-
message: '#^Method Ibexa\\Core\\Persistence\\Legacy\\Content\\FieldValue\\Converter\\DateAndTimeConverter\:\:getDateIntervalFromXML\(\) should return DateInterval but returns DateInterval\|false\.$#'
identifier: return.type
count: 1
path: src/lib/Persistence/Legacy/Content/FieldValue/Converter/DateAndTimeConverter.php

-
message: "#^Class SensitiveParameterValue not found\\.$#"
count: 1
Expand Down
12 changes: 0 additions & 12 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -66760,12 +66760,6 @@ parameters:
count: 1
path: tests/lib/Persistence/Legacy/User/Role/LimitationConverterTest.php

-
message: '#^Instanceof between Ibexa\\Contracts\\Core\\Persistence\\User\\Policy and Ibexa\\Contracts\\Core\\Persistence\\User\\Policy will always evaluate to true\.$#'
identifier: instanceof.alwaysTrue
count: 1
path: tests/lib/Persistence/Legacy/User/UserHandlerTest.php

-
message: '#^Method Ibexa\\Tests\\Core\\Persistence\\Legacy\\User\\UserHandlerTest\:\:createRole\(\) has no return type specified\.$#'
identifier: missingType.return
Expand Down Expand Up @@ -67084,12 +67078,6 @@ parameters:
count: 5
path: tests/lib/Persistence/Legacy/User/UserHandlerTest.php

-
message: '#^Right side of && is always true\.$#'
identifier: booleanAnd.rightAlwaysTrue
count: 1
path: tests/lib/Persistence/Legacy/User/UserHandlerTest.php

-
message: '#^Cannot call method fetchAll\(\) on Doctrine\\DBAL\\ForwardCompatibility\\Result\|int\|string\.$#'
identifier: method.nonObject
Expand Down
4 changes: 4 additions & 0 deletions src/lib/MVC/Symfony/Controller/Content/DownloadController.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ public function downloadBinaryFileAction(int $contentId, string $fieldIdentifier
);
}

if ($field->value->fileName !== $filename) {
throw new NotFoundException('File', $filename);
}

$response = new BinaryStreamResponse($this->ioService->loadBinaryFile($field->value->id), $this->ioService);
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Tests\Integration\Core\MVC\Symfony\Controller\Content;

use DateTime;
use Ibexa\Bundle\IO\BinaryStreamResponse;
use Ibexa\Contracts\Core\Repository\ContentService;
use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
use Ibexa\Contracts\Core\Repository\Values\Content\Field;
use Ibexa\Contracts\Core\Test\IbexaKernelTestCase;
use Ibexa\Core\FieldType\BinaryFile\Value as BinaryFileValue;
use Ibexa\Core\Helper\TranslationHelper;
use Ibexa\Core\IO\IOServiceInterface;
use Ibexa\Core\IO\Values\BinaryFile;
use Ibexa\Core\MVC\Symfony\Controller\Content\DownloadController;
use Ibexa\Core\Repository\Values\Content\Content;
use Ibexa\Core\Repository\Values\Content\VersionInfo;
use Ibexa\Tests\Integration\Core\MVC\Symfony\InternalRoutingTestKernel;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

/**
* @group integration
*
* @covers \Ibexa\Core\MVC\Symfony\Controller\Content\DownloadController
*/
final class DownloadControllerRequestFlowTest extends IbexaKernelTestCase
{
private const FILENAME = 'Q1 report #1 + 100%.jpg';

/** @var \Ibexa\Contracts\Core\Repository\ContentService&\PHPUnit\Framework\MockObject\MockObject */
private $contentService;
Comment thread
wiewiurdp marked this conversation as resolved.
Outdated

/** @var \Ibexa\Core\IO\IOServiceInterface&\PHPUnit\Framework\MockObject\MockObject */
private $ioService;

/** @var \Ibexa\Core\Helper\TranslationHelper&\PHPUnit\Framework\MockObject\MockObject */
private $translationHelper;

protected static function getKernelClass(): string
{
return InternalRoutingTestKernel::class;
}

protected function setUp(): void
{
parent::setUp();

self::bootKernel();

$this->contentService = $this->createMock(ContentService::class);
$this->ioService = $this->createMock(IOServiceInterface::class);
$this->translationHelper = $this->createMock(TranslationHelper::class);
}

public function testDownloadsFileWithUrlEncodedFilename(): void
{
$routes = $this->createRouteCollection();
$context = new RequestContext();
$url = (new UrlGenerator($routes, $context))->generate(
'ibexa.content.download',
[
'contentId' => 42,
'fieldIdentifier' => 'file',
'filename' => self::FILENAME,
'inLanguage' => 'eng-GB',
]
);

self::assertStringContainsString('Q1%20report%20%231%20+%20100%25.jpg', $url);

$content = $this->createContent();
$field = $content->getField('file', 'eng-GB');
self::assertInstanceOf(Field::class, $field);

$binaryFile = new BinaryFile([
'id' => 'binary-file-id',
'mtime' => new DateTime(),
'size' => 123,
'uri' => 'binary-file-uri',
]);

$this->contentService
->expects($this->once())
Comment thread
wiewiurdp marked this conversation as resolved.
Outdated
->method('loadContent')
->with(42)
->willReturn($content);
$this->translationHelper
->expects($this->once())
->method('getTranslatedField')
->with($content, 'file', 'eng-GB')
->willReturn($field);
$this->ioService
->expects($this->once())
->method('loadBinaryFile')
->with('binary-file-id')
->willReturn($binaryFile);

$this->configureDownloadController($routes);

$response = $this->createHttpKernel($routes, $context)->handle(
Request::create($url),
HttpKernelInterface::MAIN_REQUEST,
false
);

self::assertSame(Response::HTTP_OK, $response->getStatusCode());
self::assertInstanceOf(BinaryStreamResponse::class, $response);
}

private function configureDownloadController(RouteCollection $routes): void
{
$route = $routes->get('ibexa.content.download');
self::assertNotNull($route);
$route->setDefault('_controller', [$this->createController(), 'downloadBinaryFileAction']);
}

private function createController(): DownloadController
{
return new DownloadController(
$this->contentService,
$this->ioService,
$this->translationHelper
);
}

private function createHttpKernel(RouteCollection $routes, RequestContext $context): HttpKernel
{
$requestStack = new RequestStack();
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new RouterListener(
new UrlMatcher($routes, $context),
$requestStack,
$context
));

$controllerResolver = self::getContainer()->get('controller_resolver');
self::assertInstanceOf(ControllerResolverInterface::class, $controllerResolver);

return new HttpKernel($dispatcher, $controllerResolver, $requestStack, new ArgumentResolver());
Comment thread
wiewiurdp marked this conversation as resolved.
Outdated
}

private function createRouteCollection(): RouteCollection
{
$routes = new RouteCollection();
$routes->add('ibexa.content.download', new Route(
'/content/download/{contentId}/{fieldIdentifier}/{filename}',
[],
['contentId' => '\d+']
));

return $routes;
}

private function createContent(): Content
{
return new Content([
'internalFields' => [
new Field([
'fieldDefIdentifier' => 'file',
'languageCode' => 'eng-GB',
'value' => new BinaryFileValue([
'id' => 'binary-file-id',
'fileName' => self::FILENAME,
]),
]),
],
'versionInfo' => new VersionInfo([
'contentInfo' => new ContentInfo([
'id' => 42,
'mainLanguageCode' => 'eng-GB',
'name' => 'Test content',
'status' => ContentInfo::STATUS_PUBLISHED,
]),
]),
]);
}
}
34 changes: 34 additions & 0 deletions tests/integration/Core/MVC/Symfony/InternalRoutingTestKernel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Tests\Integration\Core\MVC\Symfony;

use Ibexa\Contracts\Core\Test\IbexaTestKernel;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class InternalRoutingTestKernel extends IbexaTestKernel
{
public function registerContainerConfiguration(LoaderInterface $loader): void
{
parent::registerContainerConfiguration($loader);

$loader->load(static function (ContainerBuilder $container): void {
self::loadRouting($container);
});
}

private static function loadRouting(ContainerBuilder $container): void
{
$container->loadFromExtension('framework', [
'router' => [
'resource' => '@IbexaCoreBundle/Resources/config/routing/internal.yml',
],
]);
}
}
Loading
Loading