Skip to content

IBX-9727: Added type-hints and adapted codebase to PHP8+ within src/bundle #1672

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
618 changes: 87 additions & 531 deletions phpstan-baseline.neon

Large diffs are not rendered by default.

19 changes: 9 additions & 10 deletions src/bundle/Command/CompileAssetsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@
name: self::COMMAND_NAME,
description: 'Compiles all assets using Webpack Encore'
)]
class CompileAssetsCommand extends Command
final class CompileAssetsCommand extends Command
{
public const COMMAND_NAME = 'ibexa:encore:compile';
public const COMMAND_DEFAULT_TIMEOUT = 300;
public const string COMMAND_NAME = 'ibexa:encore:compile';
public const int COMMAND_DEFAULT_TIMEOUT = 300;

private int $timeout;

public function __construct(int $timeout = self::COMMAND_DEFAULT_TIMEOUT)
{
$this->timeout = $timeout;
public function __construct(
private readonly int $timeout = self::COMMAND_DEFAULT_TIMEOUT
) {
parent::__construct();
}

Expand Down Expand Up @@ -96,11 +94,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if (!empty($frontendConfigsName)) {
$frontendConfigsNameArr = explode(',', $frontendConfigsName);
$yarnEncoreCommand = implode(' && ', array_map(
fn (string $configName) => "{$yarnBaseEncoreCommand} --config {$this->getFrontendConfigPath($configName)}",
fn (string $configName): string => "{$yarnBaseEncoreCommand} --config {$this->getFrontendConfigPath($configName)}",
$frontendConfigsNameArr
));
}

/** @var \Symfony\Component\Console\Helper\DebugFormatterHelper $debugFormatter */
$debugFormatter = $this->getHelper('debug_formatter');

$process = Process::fromShellCommandline(
Expand Down Expand Up @@ -138,6 +137,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
)
);

return $process->getExitCode();
return $process->getExitCode() ?? Command::FAILURE;
}
}
5 changes: 1 addition & 4 deletions src/bundle/Controller/ApplicationConfigController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@

final class ApplicationConfigController extends Controller
{
private Aggregator $aggregator;

public function __construct(Aggregator $aggregator)
public function __construct(private readonly Aggregator $aggregator)
{
$this->aggregator = $aggregator;
}

public function loadConfigAction(): ApplicationConfig
Expand Down
137 changes: 49 additions & 88 deletions src/bundle/Controller/AssetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Ibexa\AdminUi\Form\Data\Asset\ImageAssetUploadData;
use Ibexa\Contracts\AdminUi\Controller\Controller;
use Ibexa\Core\FieldType\Image\Value as ImageValue;
use Ibexa\Core\FieldType\ImageAsset\AssetMapper;
use Ibexa\Core\FieldType\ImageAsset\AssetMapper as ImageAssetMapper;
use JMS\TranslationBundle\Annotation\Desc;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand All @@ -24,92 +23,69 @@
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

class AssetController extends Controller
final class AssetController extends Controller
{
public const CSRF_TOKEN_HEADER = 'X-CSRF-Token';
public const string CSRF_TOKEN_HEADER = 'X-CSRF-Token';

public const LANGUAGE_CODE_KEY = 'languageCode';
public const FILE_KEY = 'file';
public const string LANGUAGE_CODE_KEY = 'languageCode';
public const string FILE_KEY = 'file';

private ValidatorInterface $validator;

private CsrfTokenManagerInterface $csrfTokenManager;

private AssetMapper $imageAssetMapper;

private TranslatorInterface $translator;

/**
* @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
* @param \Symfony\Component\Security\Csrf\CsrfTokenManagerInterface $csrfTokenManager
* @param \Ibexa\Core\FieldType\ImageAsset\AssetMapper $imageAssetMapper
* @param \Symfony\Contracts\Translation\TranslatorInterface $translator
*/
public function __construct(
ValidatorInterface $validator,
CsrfTokenManagerInterface $csrfTokenManager,
ImageAssetMapper $imageAssetMapper,
TranslatorInterface $translator
private readonly ValidatorInterface $validator,
private readonly CsrfTokenManagerInterface $csrfTokenManager,
private readonly ImageAssetMapper $imageAssetMapper,
private readonly TranslatorInterface $translator
) {
$this->validator = $validator;
$this->csrfTokenManager = $csrfTokenManager;
$this->imageAssetMapper = $imageAssetMapper;
$this->translator = $translator;
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
*/
public function uploadImageAction(Request $request): Response
{
if ($this->isValidCsrfToken($request)) {
$data = new ImageAssetUploadData(
$request->files->get(self::FILE_KEY),
$request->request->get(self::LANGUAGE_CODE_KEY)
);

$errors = $this->validator->validate($data);
if ($errors->count() === 0) {
try {
$file = $data->getFile();

$content = $this->imageAssetMapper->createAsset(
$file->getClientOriginalName(),
new ImageValue([
'inputUri' => $file->getRealPath(),
'fileSize' => $file->getSize(),
'fileName' => $file->getClientOriginalName(),
'alternativeText' => $file->getClientOriginalName(),
]),
$data->getLanguageCode()
);

return new JsonResponse([
'destinationContent' => [
'id' => $content->contentInfo->id,
'name' => $content->getName(),
'locationId' => $content->contentInfo->mainLocationId,
],
'value' => $this->imageAssetMapper->getAssetValue($content),
]);
} catch (Exception $e) {
return $this->createGenericErrorResponse($e->getMessage());
if (!$this->isValidCsrfToken($request)) {
return $this->createInvalidCsrfResponse();
}

$data = new ImageAssetUploadData(
$request->files->get(self::FILE_KEY),
$request->request->get(self::LANGUAGE_CODE_KEY)
);

$errors = $this->validator->validate($data);
if ($errors->count() === 0) {
try {
$file = $data->getFile();
if ($file === null) {
throw new Exception('File is missing in the request.');
}
} else {
return $this->createInvalidInputResponse($errors);

$content = $this->imageAssetMapper->createAsset(
$file->getClientOriginalName(),
new ImageValue([
'inputUri' => $file->getRealPath(),
'fileSize' => $file->getSize(),
'fileName' => $file->getClientOriginalName(),
'alternativeText' => $file->getClientOriginalName(),
]),
$data->getLanguageCode() ?? ''
);

$contentInfo = $content->getContentInfo();

return new JsonResponse([
'destinationContent' => [
'id' => $contentInfo->getId(),
'name' => $content->getName(),
'locationId' => $contentInfo->getMainLocationId(),
],
'value' => $this->imageAssetMapper->getAssetValue($content),
]);
} catch (Exception $e) {
return $this->createGenericErrorResponse($e->getMessage());
}
} else {
return $this->createInvalidInputResponse($errors);
}

return $this->createInvalidCsrfResponse();
}

/**
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
private function createInvalidCsrfResponse(): JsonResponse
{
$errorMessage = $this->translator->trans(
Expand All @@ -122,11 +98,6 @@ private function createInvalidCsrfResponse(): JsonResponse
return $this->createGenericErrorResponse($errorMessage);
}

/**
* @param \Symfony\Component\Validator\ConstraintViolationListInterface $errors
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
private function createInvalidInputResponse(ConstraintViolationListInterface $errors): JsonResponse
{
$errorMessages = [];
Expand All @@ -137,11 +108,6 @@ private function createInvalidInputResponse(ConstraintViolationListInterface $er
return $this->createGenericErrorResponse(implode(', ', $errorMessages));
}

/**
* @param string $errorMessage
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
private function createGenericErrorResponse(string $errorMessage): JsonResponse
{
return new JsonResponse(
Expand All @@ -154,11 +120,6 @@ private function createGenericErrorResponse(string $errorMessage): JsonResponse
);
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return bool
*/
private function isValidCsrfToken(Request $request): bool
{
$csrfTokenValue = $request->headers->get(self::CSRF_TOKEN_HEADER);
Expand Down
69 changes: 24 additions & 45 deletions src/bundle/Controller/BookmarkController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,41 +23,18 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class BookmarkController extends Controller
final class BookmarkController extends Controller
{
private BookmarkService $bookmarkService;

private DatasetFactory $datasetFactory;

private FormFactory $formFactory;

private LocationService $locationService;

private SubmitHandler $submitHandler;

private ConfigResolverInterface $configResolver;

public function __construct(
BookmarkService $bookmarkService,
DatasetFactory $datasetFactory,
FormFactory $formFactory,
LocationService $locationService,
SubmitHandler $submitHandler,
ConfigResolverInterface $configResolver
private readonly BookmarkService $bookmarkService,
private readonly DatasetFactory $datasetFactory,
private readonly FormFactory $formFactory,
private readonly LocationService $locationService,
private readonly SubmitHandler $submitHandler,
private readonly ConfigResolverInterface $configResolver
) {
$this->bookmarkService = $bookmarkService;
$this->datasetFactory = $datasetFactory;
$this->formFactory = $formFactory;
$this->locationService = $locationService;
$this->submitHandler = $submitHandler;
$this->configResolver = $configResolver;
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function listAction(Request $request): Response
{
/** @phpstan-var int<0, max> $page */
Expand All @@ -67,15 +44,19 @@ public function listAction(Request $request): Response
new BookmarkAdapter($this->bookmarkService, $this->datasetFactory)
);

$pagerfanta->setMaxPerPage($this->configResolver->getParameter('pagination.bookmark_limit'));
$pagerfanta->setMaxPerPage(
$this->configResolver->getParameter('pagination.bookmark_limit')
);
$pagerfanta->setCurrentPage(min($page, $pagerfanta->getNbPages()));

$editForm = $this->formFactory->contentEdit(
new ContentEditData()
);

$removeBookmarkForm = $this->formFactory->removeBookmark(
new BookmarkRemoveData($this->getChoices(iterator_to_array($pagerfanta->getCurrentPageResults())))
new BookmarkRemoveData(
$this->getChoices(iterator_to_array($pagerfanta->getCurrentPageResults()))
)
);

return $this->render(
Expand All @@ -88,11 +69,6 @@ public function listAction(Request $request): Response
);
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function removeAction(Request $request): Response
{
$form = $this->formFactory->removeBookmark(
Expand All @@ -101,15 +77,18 @@ public function removeAction(Request $request): Response
$form->handleRequest($request);

if ($form->isSubmitted()) {
$result = $this->submitHandler->handle($form, function (BookmarkRemoveData $data): RedirectResponse {
foreach ($data->getBookmarks() as $locationId => $selected) {
$this->bookmarkService->deleteBookmark(
$this->locationService->loadLocation($locationId)
);
$result = $this->submitHandler->handle(
$form,
function (BookmarkRemoveData $data): RedirectResponse {
foreach ($data->getBookmarks() as $locationId => $selected) {
$this->bookmarkService->deleteBookmark(
$this->locationService->loadLocation($locationId)
);
}

return $this->redirectToRoute('ibexa.bookmark.list');
}

return $this->redirectToRoute('ibexa.bookmark.list');
});
);

if ($result instanceof Response) {
return $result;
Expand Down
Loading
Loading