Initial release

This commit is contained in:
Jürgen Mummert
2026-02-17 18:53:23 +01:00
commit 63b5556b21
45 changed files with 3962 additions and 0 deletions
@@ -0,0 +1,384 @@
<?php
declare(strict_types=1);
namespace MummertMedia\EventManagerBundle\Controller\Frontend;
use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController;
use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule;
use Contao\CoreBundle\Twig\FragmentTemplate;
use Contao\Dbafs;
use Contao\FilesModel;
use Contao\FrontendUser;
use Contao\ModuleModel;
use Contao\PageModel;
use Contao\StringUtil;
use MummertMedia\EventManagerBundle\Form\EventType;
use MummertMedia\EventManagerBundle\Service\EventRepository;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
#[AsFrontendModule(type: 'event_edit', category: 'eventmanager', template: 'frontend/event_edit')]
class EventEditController extends AbstractFrontendModuleController
{
public function __construct(
private readonly EventRepository $eventRepository,
) {
}
protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response
{
$user = $this->getUser();
$backUrl = $this->resolveBackUrl($request, $model);
$eventParam = $request->query->get('event');
$isCreateMode = '1' === (string) $request->query->get('create', '0') && (null === $eventParam || (int) $eventParam <= 0);
if (!$user instanceof FrontendUser) {
$template->set('error', 'Bitte zuerst als Mitglied einloggen.');
$template->set('backUrl', $backUrl);
return $template->getResponse();
}
$eventId = $isCreateMode ? 0 : (int) $eventParam;
$event = null;
if (!$isCreateMode) {
if ($eventId <= 0 || !$this->eventRepository->memberHasEvent((int) $user->id, $eventId)) {
$template->set('error', 'Keine Berechtigung für diese Veranstaltung oder ungültige ID.');
$template->set('backUrl', $backUrl);
return $template->getResponse();
}
$event = $this->eventRepository->findById($eventId);
if (null === $event) {
$template->set('error', 'Veranstaltung nicht gefunden.');
$template->set('backUrl', $backUrl);
return $template->getResponse();
}
}
if ($isCreateMode) {
$event = [
'title' => '',
'startDate' => null,
'endDate' => null,
'addTime' => '',
'startTime' => null,
'endTime' => null,
'location_id' => 0,
'type' => null,
'teaser' => '',
'description' => '',
'url' => '',
'photographer' => '',
'addImage' => '',
'termsAccepted' => '',
'isSoldOut' => '',
'isCanceled' => '',
'published' => '',
'singleSRC' => null,
];
}
$memberOrganizationIds = $this->eventRepository->getOrganizationIdsForMember((int) $user->id);
$organizationChoices = $this->eventRepository->getOrganizationChoicesForMember((int) $user->id);
$showOrganization = count($memberOrganizationIds) > 1;
$currentOrganizationIds = $this->eventRepository->getOrganizationIdsForEvent($eventId);
$formData = [
'title' => (string) ($event['title'] ?? ''),
'startDate' => !empty($event['startDate']) ? date('Y-m-d', (int) $event['startDate']) : '',
'endDate' => !empty($event['endDate']) ? date('Y-m-d', (int) $event['endDate']) : '',
'addTime' => '1' === (string) ($event['addTime'] ?? ''),
'startTime' => ('1' === (string) ($event['addTime'] ?? '') && !empty($event['startTime'])) ? date('H:i', (int) $event['startTime']) : '',
'endTime' => $this->resolveFormEndTime($event),
'location_id' => (int) ($event['location_id'] ?? 0),
'type' => StringUtil::deserialize($event['type'] ?? null, true),
'teaser' => (string) ($event['teaser'] ?? ''),
'description' => (string) ($event['description'] ?? ''),
'url' => (string) ($event['url'] ?? ''),
'photographer' => (string) ($event['photographer'] ?? ''),
'addImage' => '1' === (string) ($event['addImage'] ?? ''),
'termsAccepted' => '1' === (string) ($event['termsAccepted'] ?? ''),
'isSoldOut' => '1' === (string) ($event['isSoldOut'] ?? ''),
'isCanceled' => '1' === (string) ($event['isCanceled'] ?? ''),
'published' => '1' === (string) ($event['published'] ?? ''),
];
if ($showOrganization) {
$allowedOrganizationIds = array_values(array_unique(array_map('intval', $memberOrganizationIds)));
$selectedOrganizationIds = array_values(array_intersect($currentOrganizationIds, $allowedOrganizationIds));
if ([] === $selectedOrganizationIds && [] !== $allowedOrganizationIds) {
$selectedOrganizationIds = [(int) $allowedOrganizationIds[0]];
}
$formData['organization_ids'] = $selectedOrganizationIds;
}
$currentImagePath = null;
if (!empty($event['singleSRC'])) {
$imageModel = FilesModel::findByUuid((string) $event['singleSRC']);
if (null !== $imageModel) {
$currentImagePath = $imageModel->path;
}
}
$form = $this->createForm(EventType::class, $formData, [
'location_choices' => $this->eventRepository->getLocationChoices(),
'organization_choices' => $organizationChoices,
'selected_organization_ids' => $showOrganization ? ($formData['organization_ids'] ?? []) : [],
'show_organization' => $showOrganization,
'terms_page_url' => $this->resolveTermsPageUrl($model),
]);
$form->handleRequest($request);
if ($form->isSubmitted()) {
$submittedData = (array) $form->getData();
if (!empty($submittedData['addImage']) && '' === trim((string) ($submittedData['photographer'] ?? ''))) {
$form->get('photographer')->addError(new FormError('Die Angabe des Urhebers ist notwendig. Ihnen muss eine Genehmigung zur Verwendung des Bildes vorliegen.'));
}
if (!empty($submittedData['addTime']) && '' === trim((string) ($submittedData['startTime'] ?? ''))) {
$form->get('startTime')->addError(new FormError('Bitte geben Sie eine Startzeit an.'));
}
}
if ($form->isSubmitted() && $form->isValid()) {
$submittedData = (array) $form->getData();
$selectedOrganizationIds = [];
if ($showOrganization) {
$selectedOrganizationIds = array_map('intval', (array) $form->get('organization_ids')->getData());
} elseif ([] !== $memberOrganizationIds) {
$selectedOrganizationIds = [(int) $memberOrganizationIds[0]];
}
$allowedOrganizationIds = array_values(array_unique(array_map('intval', $memberOrganizationIds)));
$selectedOrganizationIds = array_values(array_intersect($selectedOrganizationIds, $allowedOrganizationIds));
if ([] === $selectedOrganizationIds) {
if ($showOrganization) {
$form->get('organization_ids')->addError(new FormError('Bitte mindestens eine Organisation auswählen.'));
} else {
$form->addError(new FormError('Keine gültige Veranstalter-Zuordnung vorhanden.'));
}
}
if ($form->isSubmitted() && !$form->isValid()) {
$template->set('form', $form->createView());
$template->set('backUrl', $backUrl);
$template->set('requestToken', $this->container->get('contao.csrf.token_manager')->getDefaultTokenValue());
$template->set('currentImagePath', $currentImagePath);
return $template->getResponse();
}
if ($isCreateMode) {
$createdEventId = $this->eventRepository->createForMember(
(int) $user->id,
(int) ($model->frontendAuthorId ?? 0),
(int) ($model->frontendArchiveId ?? 0),
$submittedData,
$selectedOrganizationIds,
);
if (null === $createdEventId) {
$form->addError(new FormError('Die Veranstaltung konnte nicht erstellt werden.'));
$template->set('form', $form->createView());
$template->set('backUrl', $backUrl);
$template->set('requestToken', $this->container->get('contao.csrf.token_manager')->getDefaultTokenValue());
$template->set('currentImagePath', $currentImagePath);
return $template->getResponse();
}
$eventId = $createdEventId;
} else {
if ($showOrganization) {
$this->eventRepository->assignEventToOrganizations($eventId, $selectedOrganizationIds);
}
$this->eventRepository->update($eventId, $submittedData);
}
$useImage = !empty($submittedData['addImage']);
$removeImage = '1' === (string) $request->request->get('remove_image', '0');
$uploadedImage = $form->get('eventUpload')->getData();
if (!$useImage) {
$this->eventRepository->updateImageFields($eventId, false, null);
} elseif ($uploadedImage instanceof UploadedFile) {
$newImageUuid = $this->storeEventImage($uploadedImage, $model, $eventId);
if (null !== $newImageUuid) {
$this->eventRepository->updateImageFields($eventId, true, $newImageUuid);
}
} elseif ($removeImage) {
$this->eventRepository->updateImageFields($eventId, true, null);
}
if ($request->request->has('save_back')) {
return new RedirectResponse($backUrl);
}
if ($isCreateMode) {
return new RedirectResponse($this->buildEventEditUrl($eventId, $backUrl));
}
return new RedirectResponse($request->getUri());
}
$template->set('form', $form->createView());
$template->set('backUrl', $backUrl);
$template->set('requestToken', $this->container->get('contao.csrf.token_manager')->getDefaultTokenValue());
$template->set('currentImagePath', $currentImagePath);
return $template->getResponse();
}
private function storeEventImage(UploadedFile $uploadedFile, ModuleModel $model, int $eventId): ?string
{
if (empty($model->eventFolder)) {
return null;
}
$folderModel = FilesModel::findByUuid((string) $model->eventFolder);
if (null === $folderModel) {
return null;
}
$organization = $this->eventRepository->findPrimaryOrganizationForEvent($eventId);
if (null === $organization) {
return null;
}
$titleSlug = strtolower(StringUtil::generateAlias((string) $organization['title']));
$titleSlug = preg_replace('/[^a-z0-9-]+/', '-', $titleSlug ?? '') ?? '';
$titleSlug = trim($titleSlug, '-');
$titleSlug = substr($titleSlug, 0, 12);
if ('' === $titleSlug) {
$titleSlug = 'organization';
}
$uploadBasePath = trim((string) $folderModel->path, '/');
if ('' === $uploadBasePath) {
return null;
}
$targetRelativeDir = sprintf('%s/org-%d-%s', $uploadBasePath, (int) $organization['id'], $titleSlug);
$projectDir = (string) $this->getParameter('kernel.project_dir');
$targetAbsoluteDir = rtrim($projectDir, '/').'/'.$targetRelativeDir;
if (!is_dir($targetAbsoluteDir) && !mkdir($targetAbsoluteDir, 0775, true) && !is_dir($targetAbsoluteDir)) {
return null;
}
$originalName = pathinfo($uploadedFile->getClientOriginalName(), PATHINFO_FILENAME);
$safeName = preg_replace('/[^a-zA-Z0-9_-]+/', '-', (string) $originalName);
$safeName = trim((string) $safeName, '-');
if ('' === $safeName) {
$safeName = 'event-image';
}
$extension = $uploadedFile->guessExtension() ?: $uploadedFile->getClientOriginalExtension() ?: 'bin';
$filename = sprintf('%s-%s.%s', $safeName, uniqid('', true), strtolower((string) $extension));
$uploadedFile->move($targetAbsoluteDir, $filename);
$relativePath = $targetRelativeDir.'/'.$filename;
$fileModel = Dbafs::addResource($relativePath);
return null !== $fileModel ? (string) $fileModel->uuid : null;
}
private function resolveBackUrl(Request $request, ModuleModel $model): string
{
if ((int) ($model->listPage ?? 0) > 0) {
$listPage = $this->getContaoAdapter(PageModel::class)->findById((int) $model->listPage);
if ($listPage instanceof PageModel) {
return $this->generateContentUrl($listPage);
}
}
$ref = (string) $request->query->get('ref', '');
if ('' !== $ref) {
$decoded = base64_decode($ref, true);
if (false !== $decoded && str_starts_with($decoded, '/')) {
return $decoded;
}
}
$page = $this->getPageModel();
return $page instanceof PageModel ? $this->generateContentUrl($page) : '/';
}
private function resolveTermsPageUrl(ModuleModel $model): ?string
{
if ((int) ($model->termsPage ?? 0) <= 0) {
return null;
}
$termsPage = $this->getContaoAdapter(PageModel::class)->findById((int) $model->termsPage);
if (!$termsPage instanceof PageModel) {
return null;
}
return $this->generateContentUrl($termsPage);
}
private function buildEventEditUrl(int $eventId, string $backUrl): string
{
$page = $this->getPageModel();
if (!$page instanceof PageModel) {
return '/';
}
return $this->generateContentUrl($page, [
'event' => (string) $eventId,
'ref' => base64_encode($backUrl),
]);
}
private function resolveFormEndTime(array $event): string
{
if ('1' !== (string) ($event['addTime'] ?? '')) {
return '';
}
$startTime = (int) ($event['startTime'] ?? 0);
$endTime = (int) ($event['endTime'] ?? 0);
if ($endTime <= 0 || $startTime <= 0) {
return '';
}
if ($endTime === $startTime || $endTime - $startTime === 86399) {
return '';
}
return date('H:i', $endTime);
}
}
@@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
namespace MummertMedia\EventManagerBundle\Controller\Frontend;
use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController;
use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule;
use Contao\CoreBundle\Twig\FragmentTemplate;
use Contao\FrontendUser;
use Contao\ModuleModel;
use Contao\PageModel;
use Contao\StringUtil;
use MummertMedia\EventManagerBundle\Service\EventRepository;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
#[AsFrontendModule(type: 'member_events', category: 'eventmanager', template: 'frontend/member_events')]
class MemberEventsController extends AbstractFrontendModuleController
{
public function __construct(
private readonly EventRepository $eventRepository,
) {
}
protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response
{
$user = $this->getUser();
if (!$user instanceof FrontendUser) {
$template->set('upcomingEvents', []);
$template->set('pastEvents', []);
$template->set('isEditor', false);
return $template->getResponse();
}
$isEditor = $this->isEditor($user);
$editPage = null;
if ((int) ($model->editPage ?? 0) > 0) {
$editPage = $this->getContaoAdapter(PageModel::class)->findById((int) $model->editPage);
}
$currentPage = $this->getPageModel();
$backUrl = $currentPage instanceof PageModel ? $this->generateContentUrl($currentPage) : '/';
if ($isEditor && 'POST' === $request->getMethod() && $request->request->has('action')) {
$action = (string) $request->request->get('action', '');
$eventId = (int) $request->request->get('event_id', 0);
if (!in_array($action, ['create', 'toggle_published', 'duplicate', 'delete'], true)) {
return $template->getResponse();
}
if ('create' === $action && $editPage instanceof PageModel) {
return new RedirectResponse($this->generateContentUrl($editPage, [
'create' => '1',
'ref' => base64_encode($backUrl),
]));
}
if ($eventId > 0 && $this->eventRepository->memberHasEvent((int) $user->id, $eventId)) {
if ('toggle_published' === $action) {
$this->eventRepository->togglePublished($eventId);
} elseif ('duplicate' === $action) {
$this->eventRepository->duplicate($eventId);
} elseif ('delete' === $action) {
$this->eventRepository->delete($eventId);
}
}
return new RedirectResponse($request->getUri());
}
$events = $this->eventRepository->findByMemberId((int) $user->id);
$upcomingItems = [];
$pastItems = [];
$today = strtotime('today');
foreach ($events as $event) {
$editUrl = null;
if ($isEditor && $editPage instanceof PageModel) {
$editUrl = $this->generateContentUrl($editPage, [
'event' => (string) $event['id'],
'ref' => base64_encode($backUrl),
]);
}
$item = [
'id' => (int) $event['id'],
'title' => (string) ($event['title'] ?? ''),
'startDate' => (int) ($event['startDate'] ?? 0),
'published' => '1' === (string) ($event['published'] ?? ''),
'editUrl' => $editUrl,
];
if ((int) $item['startDate'] >= $today) {
$upcomingItems[] = $item;
} else {
$pastItems[] = $item;
}
}
usort(
$upcomingItems,
static fn (array $a, array $b): int => ((int) $b['startDate']) <=> ((int) $a['startDate']),
);
usort(
$pastItems,
static fn (array $a, array $b): int => ((int) $b['startDate']) <=> ((int) $a['startDate']),
);
$template->set('upcomingEvents', $upcomingItems);
$template->set('pastEvents', $pastItems);
$template->set('isEditor', $isEditor);
$template->set('canCreateEvent', $isEditor && $editPage instanceof PageModel);
$template->set('requestToken', $this->container->get('contao.csrf.token_manager')->getDefaultTokenValue());
return $template->getResponse();
}
private function isEditor(FrontendUser $user): bool
{
$groups = is_array($user->groups) ? $user->groups : StringUtil::deserialize($user->groups, true);
return in_array(1, array_map('intval', $groups), true);
}
}
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace MummertMedia\EventManagerBundle\Controller\Frontend;
use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController;
use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule;
use Contao\CoreBundle\Twig\FragmentTemplate;
use Contao\FrontendUser;
use Contao\ModuleModel;
use Contao\PageModel;
use Contao\StringUtil;
use MummertMedia\EventManagerBundle\Service\OrganizationRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
#[AsFrontendModule(type: 'member_organizations', category: 'eventmanager', template: 'frontend/member_organizations')]
class MemberOrganizationsController extends AbstractFrontendModuleController
{
public function __construct(
private readonly OrganizationRepository $organizationRepository,
) {
}
protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response
{
$user = $this->getUser();
if (!$user instanceof FrontendUser) {
$template->set('organizations', []);
return $template->getResponse();
}
$organizations = $this->organizationRepository->findByMemberId((int) $user->id);
$isEditor = $this->isEditor($user);
$editPage = null;
if ((int) ($model->editPage ?? 0) > 0) {
$editPage = $this->getContaoAdapter(PageModel::class)->findById((int) $model->editPage);
}
$currentPage = $this->getPageModel();
$backUrl = $currentPage instanceof PageModel ? $this->generateContentUrl($currentPage) : '/';
$items = [];
foreach ($organizations as $organization) {
$editUrl = null;
if ($isEditor && $editPage instanceof PageModel) {
$editUrl = $this->generateContentUrl($editPage, [
'organization' => (string) $organization['id'],
'ref' => base64_encode($backUrl),
]);
}
$items[] = [
'id' => (int) $organization['id'],
'title' => (string) ($organization['title'] ?? ''),
'editUrl' => $editUrl,
];
}
$template->set('organizations', $items);
return $template->getResponse();
}
private function isEditor(FrontendUser $user): bool
{
$groups = is_array($user->groups) ? $user->groups : StringUtil::deserialize($user->groups, true);
return in_array(1, array_map('intval', $groups), true);
}
}
@@ -0,0 +1,212 @@
<?php
declare(strict_types=1);
namespace MummertMedia\EventManagerBundle\Controller\Frontend;
use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController;
use Contao\CoreBundle\DependencyInjection\Attribute\AsFrontendModule;
use Contao\CoreBundle\Twig\FragmentTemplate;
use Contao\Dbafs;
use Contao\FilesModel;
use Contao\FrontendUser;
use Contao\ModuleModel;
use Contao\PageModel;
use Contao\StringUtil;
use MummertMedia\EventManagerBundle\Form\OrganizationType;
use MummertMedia\EventManagerBundle\Service\OrganizationRepository;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
#[AsFrontendModule(type: 'organization_edit', category: 'eventmanager', template: 'frontend/organization_edit')]
class OrganizationEditController extends AbstractFrontendModuleController
{
public function __construct(
private readonly OrganizationRepository $organizationRepository,
) {
}
protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response
{
$user = $this->getUser();
$backUrl = $this->resolveBackUrl($request, $model);
$organizationParam = $request->query->get('organization');
if (null === $organizationParam) {
$template->set('error', 'Ungültiger Aufruf: Parameter "organization" fehlt.');
$template->set('backUrl', $backUrl);
return $template->getResponse();
}
if (!$user instanceof FrontendUser) {
$template->set('error', 'Bitte zuerst als Mitglied einloggen.');
$template->set('backUrl', $backUrl);
return $template->getResponse();
}
$organizationId = (int) $organizationParam;
if ($organizationId <= 0 || !$this->organizationRepository->memberHasOrganization((int) $user->id, $organizationId)) {
$template->set('error', 'Keine Berechtigung für diese Organisation oder ungültige ID.');
$template->set('backUrl', $backUrl);
return $template->getResponse();
}
$organization = $this->organizationRepository->findById($organizationId);
if (null === $organization) {
$template->set('error', 'Organisation nicht gefunden.');
$template->set('backUrl', $backUrl);
return $template->getResponse();
}
$formData = [
'title' => (string) ($organization['title'] ?? ''),
'street' => (string) ($organization['street'] ?? ''),
'postal' => (string) ($organization['postal'] ?? ''),
'city' => (string) ($organization['city'] ?? ''),
'state' => (string) ($organization['state'] ?? ''),
'country' => (string) ($organization['country'] ?? ''),
'phone' => (string) ($organization['phone'] ?? ''),
'email' => (string) ($organization['email'] ?? ''),
'website' => (string) ($organization['website'] ?? ''),
'description' => (string) ($organization['description'] ?? ''),
'type' => StringUtil::deserialize($organization['type'] ?? null, true),
];
$currentLogoPath = null;
if (!empty($organization['logo'])) {
$logoModel = FilesModel::findByUuid((string) $organization['logo']);
if (null !== $logoModel) {
$currentLogoPath = $logoModel->path;
}
}
$form = $this->createForm(OrganizationType::class, $formData);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$submittedData = (array) $form->getData();
$this->organizationRepository->update($organizationId, $submittedData);
$deleteLogo = '1' === (string) $request->request->get('remove_logo', '0');
$uploadedLogo = $form->get('logoUpload')->getData();
if ($uploadedLogo instanceof UploadedFile) {
$newLogoUuid = $this->storeOrganizationLogo(
$uploadedLogo,
$model,
$organizationId,
(string) ($submittedData['title'] ?? ''),
);
if (null !== $newLogoUuid) {
$this->organizationRepository->updateLogo($organizationId, $newLogoUuid);
}
} elseif ($deleteLogo) {
$this->organizationRepository->updateLogo($organizationId, null);
}
if ($request->request->has('save_back')) {
return new RedirectResponse($backUrl);
}
return new RedirectResponse($request->getUri());
}
$template->set('form', $form->createView());
$template->set('backUrl', $backUrl);
$template->set('requestToken', $this->container->get('contao.csrf.token_manager')->getDefaultTokenValue());
$template->set('currentLogoPath', $currentLogoPath);
return $template->getResponse();
}
private function storeOrganizationLogo(UploadedFile $uploadedFile, ModuleModel $model, int $organizationId, string $organizationTitle): ?string
{
if (empty($model->logoFolder)) {
return null;
}
$folderModel = FilesModel::findByUuid((string) $model->logoFolder);
if (null === $folderModel) {
return null;
}
$uploadBasePath = trim((string) $folderModel->path, '/');
if ('' === $uploadBasePath) {
return null;
}
$titleSlug = strtolower(StringUtil::generateAlias($organizationTitle));
$titleSlug = preg_replace('/[^a-z0-9-]+/', '-', $titleSlug ?? '') ?? '';
$titleSlug = trim($titleSlug, '-');
$titleSlug = substr($titleSlug, 0, 12);
if ('' === $titleSlug) {
$titleSlug = 'organization';
}
$targetRelativeDir = sprintf('%s/org-%d-%s', $uploadBasePath, $organizationId, $titleSlug);
$projectDir = (string) $this->getParameter('kernel.project_dir');
$targetAbsoluteDir = rtrim($projectDir, '/').'/'.$targetRelativeDir;
if (!is_dir($targetAbsoluteDir) && !mkdir($targetAbsoluteDir, 0775, true) && !is_dir($targetAbsoluteDir)) {
return null;
}
$originalName = pathinfo($uploadedFile->getClientOriginalName(), PATHINFO_FILENAME);
$safeName = preg_replace('/[^a-zA-Z0-9_-]+/', '-', (string) $originalName);
$safeName = trim((string) $safeName, '-');
if ('' === $safeName) {
$safeName = 'logo';
}
$extension = $uploadedFile->guessExtension() ?: $uploadedFile->getClientOriginalExtension() ?: 'bin';
$filename = sprintf('%s-%s.%s', $safeName, uniqid('', true), strtolower((string) $extension));
$uploadedFile->move($targetAbsoluteDir, $filename);
$relativePath = $targetRelativeDir.'/'.$filename;
$fileModel = Dbafs::addResource($relativePath);
return null !== $fileModel ? (string) $fileModel->uuid : null;
}
private function resolveBackUrl(Request $request, ModuleModel $model): string
{
if ((int) ($model->listPage ?? 0) > 0) {
$listPage = $this->getContaoAdapter(PageModel::class)->findById((int) $model->listPage);
if ($listPage instanceof PageModel) {
return $this->generateContentUrl($listPage);
}
}
$ref = (string) $request->query->get('ref', '');
if ('' !== $ref) {
$decoded = base64_decode($ref, true);
if (false !== $decoded && str_starts_with($decoded, '/')) {
return $decoded;
}
}
$page = $this->getPageModel();
return $page instanceof PageModel ? $this->generateContentUrl($page) : '/';
}
}