<?php
namespace Bidcoz\Bundle\FrontendBundle\Controller;
use Bidcoz\Bundle\CoreBundle\Constants;
use Bidcoz\Bundle\CoreBundle\Controller\CoreController;
use Bidcoz\Bundle\CoreBundle\Entity\Auction\Auction;
use Bidcoz\Bundle\CoreBundle\Entity\Auction\FundANeed;
use Bidcoz\Bundle\CoreBundle\Entity\Auction\Shop;
use Bidcoz\Bundle\CoreBundle\Entity\Campaign;
use Bidcoz\Bundle\CoreBundle\Entity\Organization;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
# TODO: New authenticator behaves differently for @Security and @IsGranted
# Issue: "Symfony\Component\Security\Core\Exception\AccessDeniedException: No user token or you forgot to put your controller behind a firewall while using a @Security tag
# PR fixes this (still "Open"): https://github.com/sensiolabs/SensioFrameworkExtraBundle/pull/763
# Docs: https://symfony.com/doc/5.2/security/experimental_authenticators.html#enabling-the-system
# Notes: When PR gets merged, switch back to using the @Security tag: @Security("is_granted('VIEW', organization) and is_granted('FRONT_END', campaign)")
/**
* @Route("/{orgSlug}/{campaignSlug}", requirements={"orgSlug" = Constants::RESERVED_SLUG_REGEX, "campaignSlug" = Constants::RESERVED_CAMPAIGN_SLUG_REGEX})
* @IsGranted("VIEW", subject="organization")
* @IsGranted("FRONT_END", subject="campaign")
*/
class CampaignController extends CoreController
{
/**
* @Route("", name="campaign_home", methods={"GET"})
* @Route("/home", methods={"GET"})
*/
public function indexAction(Organization $organization, Campaign $campaign, Auction $auction = null, Shop $shop = null, FundANeed $fund_a_need = null)
{
$featuredItems = $auction
? $this->getRepository('Auction\Item')->findFeaturedItems($auction)
: [];
$shopItems = $shop
? $this->getRepository('Auction\Item')->findFeaturedItems($shop)
: [];
$fundANeedItems = $fund_a_need
? $this->getRepository('Auction\Item')->findFeaturedItems($fund_a_need)
: [];
// 2026 redesign: dispatch to a per-layout template based on the theme's
// themeName. Mirrors the template-side resolution in Layout/layout.html.twig
// (campaign theme first, then organization theme). 'centered-alt' (Boxed
// Width with Medium Logo) is an offered option that maps to the legacy
// index.html.twig. Legacy 'wide' (hidden from the picker) and any other
// unrecognized/null themeName fall back to Landing Page Hero, which most
// closely resembles the old banner layout, so existing campaigns keep
// working with a modern layout instead of the deprecated index.html.twig.
$theme = $campaign->getTheme() ?: $organization->getTheme();
$themeName = $theme ? $theme->getThemeName() : null;
$templatesByThemeName = [
'story-first' => '@BidcozFrontend/Campaign/Templates/StoryFirst/index.html.twig',
'landing-hero' => '@BidcozFrontend/Campaign/Templates/LandingHero/index.html.twig',
'bold-split' => '@BidcozFrontend/Campaign/Templates/BoldSplit/index.html.twig',
// Restored 4th picker option: renders the legacy boxed layout, not
// the Landing Page Hero fallback below.
'centered-alt' => '@BidcozFrontend/Campaign/index.html.twig',
];
$template = $templatesByThemeName[$themeName] ?? '@BidcozFrontend/Campaign/Templates/LandingHero/index.html.twig';
return $this->render($template, [
'organization' => $organization,
'campaign' => $campaign,
'auction' => $auction,
'featuredItems' => $featuredItems,
'shopItems' => $shopItems,
'fundANeedItems' => $fundANeedItems,
]);
}
/**
* @Route("/details", name="campaign_details")
*/
public function detailsAction(Organization $organization, Campaign $campaign)
{
return $this->render('@BidcozFrontend/Campaign/details.html.twig', [
'organization' => $organization,
'campaign' => $campaign,
]);
}
/**
* @Route("/rules", name="campaign_rules")
*/
public function rulesAction(Organization $organization, Campaign $campaign)
{
$rules = $this->getRepository('Rule')->findAll();
return $this->render('@BidcozFrontend/Campaign/rules.html.twig', [
'organization' => $organization,
'campaign' => $campaign,
'rules' => $rules,
]);
}
/**
* @Route("/button/{component}", name="campaign_external_button")
*/
public function buttonAction(Request $request, Organization $organization, Campaign $campaign, $component)
{
// If the button is for nvidia, set the host
if ('nvidia' === $organization->getSlug()) {
$context = $this->getRouter()->getContext();
$context->setHost('nvidia.causepilot.com');
}
return $this->render('@BidcozFrontend/Campaign/Marketing/button.html.twig', [
'organization' => $organization,
'campaign' => $campaign,
'component' => $component,
]);
}
/**
* @Route("/qr-code", name="campaign_external_qrcode")
*/
public function qrCodeAction(Request $request, Organization $organization, Campaign $campaign)
{
return $this->render('@BidcozFrontend/Campaign/Marketing/qrcode.html.twig', [
'organization' => $organization,
'campaign' => $campaign,
]);
}
}