<?php
namespace Bidcoz\Bundle\FrontendBundle\Controller;
use Bidcoz\Bundle\CoreBundle\Controller\CoreController;
use Bidcoz\Bundle\CoreBundle\Entity\Organization;
use Bidcoz\Bundle\CoreBundle\Event\CoreEvents;
use Bidcoz\Bundle\CoreBundle\Event\OrganizationEvent;
use Bidcoz\Bundle\CoreBundle\Services\MailchimpManager;
use Bidcoz\Bundle\FrontendBundle\Form\Type\OrganizationType;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/organization")
*/
class OrganizationRegistrationController extends CoreController
{
/**
* @Route("/register/new", name="organization_register")
*/
public function register(Request $request)
{
$user = $this->getUser();
// Restored (CAU-253 #15). setupOrganization() type-hints User, so reaching a
// POST without one is a TypeError 500 rather than anything a person can act on.
if (!$user) {
$this->messageAccessDeniedException('You must login or create an account to register a new organization');
}
$organization = $this->createOrganization();
$form = $this->createForm(OrganizationType::class, $organization);
if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// CAU-417 (Option 1): the real organizationType is now persisted from the
// form. To keep behaviour identical to before, every self-serve org stays
// flagged non_profit=true regardless of type (previously done implicitly by
// the hidden 'non-profit' input). Mapping type -> nonprofit/fundraising
// eligibility is deferred to the future org.canFundraise work.
$organization->setNonProfit(true);
$this->getEntityManager()->persist($organization);
try {
$organization->ensureSlugLowercase();
$this->getOrganizationManager()->setupOrganization($organization, $user);
// Safety net (CAU-253 #15). The organization_admins row created here
// is the ONLY thing that makes the new account reachable — the manage
// dashboard is @IsGranted("MANAGE"), and OrganizationVoter grants that
// solely off this link. If it ever goes missing, the signup still looks
// successful and the failure surfaces one redirect later as a bare 403
// on an account the person just created, with nothing in the logs
// pointing back here. Assert it twice so it fails at its origin instead:
// once in memory, BEFORE the flush, so a broken link aborts without
// stranding a half-created account...
$linked = false;
foreach ($organization->getAdmins() as $admin) {
if ($admin->getUser() === $user) {
$linked = true;
break;
}
}
if (!$linked) {
throw new \RuntimeException(sprintf(
'Organization signup aborted: no admin link was created for user %s on "%s". Creating the account would have produced an org nobody can open.',
$user->getId(),
$organization->getSlug()
));
}
$event = $this->createEvent($organization);
$this->getEventDispatcher()->dispatch($event, CoreEvents::ORGANIZATION_CREATED);
$this->getEntityManager()->flush();
// ...and once against the database after it, since an ORPHANED
// organization is only fixable by hand and we need to know which one.
// Read through the manager's repository (not its isOrganizationAdmin
// cache) so this is a real query, not a memoized answer.
if (!$this->getOrganizationManager()->getOrganizationAdmin($organization, $user)) {
throw new \RuntimeException(sprintf(
'Organization "%s" (id %s) was created but no organization_admins row exists for user %s. The account is orphaned and unreachable.',
$organization->getSlug(),
$organization->getId(),
$user->getId()
));
}
$this->addFlash('success', 'Organization Created');
$this->getMailChimpManager()->addUserToOnboardingJourney($user,[MailchimpManager::TAG_NEW_CUSTOMER],$organization);
// If creating a new org, remove any traces to previous campaigns/orgs
$this->getSession()->remove('viewed_campaign');
$this->getSession()->remove('viewed_organization');
return $this->redirectToRoute('organization_manage_dashboard', [
'orgSlug' => $organization->getSlug(),
'welcome' => 1,
'_first_load' => 1,
]);
} catch (UniqueConstraintViolationException $e) {
$form->get('slug')->addError(new FormError('This account URL is already taken'));
}
} else {
$this->addFlash('danger', 'There was an error creating your account');
}
}
return $this->render('@BidcozFrontend/Marketing/register.html.twig', [
'form' => $form->createView(),
]);
}
protected function createEvent(Organization $organization)
{
return new OrganizationEvent($organization);
}
protected function createOrganization()
{
return $this->getOrganizationManager()->createOrganization();
}
}