简体   繁体   中英

FOS UserBundle adding needed functionality to the registration

I feel that I have greatly exhausted Google and Fos UserBundle's documentation searching for a way to initialize the basic Entities needed when registering a new user. I have overridden the RegistrationController:register method and am attempting to initialize and add an entity called "Humidor" to the User. This is how it currently appears.

    <?php

namespace UserBundle\Controller;

use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\RegistrationController as BaseController;
use AppBundle\Entity\Humidor;
use Symfony\Component\HttpFoundation\Request;

use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Form\Factory\FactoryInterface;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Model\UserInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

class RegistrationController extends BaseController
{
    public function registerAction(Request $request)
    {


        /** @var $formFactory FactoryInterface */
        $formFactory = $this->get('fos_user.registration.form.factory');
        /** @var $userManager UserManagerInterface */
        $userManager = $this->get('fos_user.user_manager');
        /** @var $dispatcher EventDispatcherInterface */
        $dispatcher = $this->get('event_dispatcher');

        $user = $userManager->createUser();
        $user->setEnabled(true);

        $event = new GetResponseUserEvent($user, $request);
        $dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, $event);

        if (null !== $event->getResponse()) {
            return $event->getResponse();
        }

        $form = $formFactory->createForm();
        $form->setData($user);

        $form->handleRequest($request);

        if ($form->isSubmitted()) {
            if ($form->isValid()) {
                $event = new FormEvent($form, $request);
                $dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
                $humidor = new Humidor();
                $user->addHumidor($humidor);

                $userManager->updateUser($user);

                if (null === $response = $event->getResponse()) {
                    $url = $this->getParameter('fos_user.registration.confirmation.enabled')
                        ? $this->generateUrl('fos_user_registration_confirmed')
                        : $this->generateUrl('fos_user_profile_show');

                    $response = new RedirectResponse($url);
                }

                $dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));

                return $response;
            }

            $event = new FormEvent($form, $request);
            $dispatcher->dispatch(FOSUserEvents::REGISTRATION_FAILURE, $event);

            if (null !== $response = $event->getResponse()) {
                return $response;
            }
        }

        return $this->render('FOSUserBundle:Registration:register.html.twig', array(
            'form' => $form->createView(),
        ));
    }
}

when trying to add call addHumidors() which is a method of my custom User entity extending BaseUser, I noticed php storm suggested all of the default User methods but none from my custom user so something is obviously wrong. Any advice on how I can hook into my custom User class from my custom registration action or even an opinion on a better way to implement this functionality would be superb. Thank you

First things first: Since all you do is new Humidor() on an unitiailized user. You could also make this part of the constructor. This is similar to how Doctrine recommends using Collections:

class User extends BaseUser
{
     public function __construct(Humidor $humidor = null)
     {
         // Doctrine recommends this for ToMany-associations:
         $this->humidors = new ArrayCollection();
         if (null === $humidor) {
             $humidor = new Humidor();
         }
         $this->addHumidor($humidor);
     }

     // [...the rest of your code...]
}

This way you will always have this object available, even on an uninitialized user. You can play around with this whatever your needs are. You could pass an array instead of a single "default" humidor or you could also adjust getHumidors() to check if it's empty and then create the default one. In any case, dealing with this inside the User gives you the advantage to easily change the default behavior in one class (instead of all the controllers where you call addHumidor() . It will make sure that you will always have the (default?) empty humidor available.

Second, regarding:

I noticed php storm suggested all of the default User methods but none from my custom user so something is obviously wrong

PhpStorm just guesses the output from methods and therefore what kind of object it is. In your case you are using the EntityManager which in it's interface refers to a UserInterface, which is also used in the doc block.

If you check FosUserBundle\\Model\\UserManagerInterface::createUser() you will notice the docblock contains @return UserInterface . This is where PhpStorm gets what kind of object your UserManager returns and since your User-class has more methods than the interface such as addHumidor PhpStorm will not know of them. If you want to tell PhpStorm that there is a concrete object with more methods (ie your User-class) you can just do the following when you call createUser:

/** @var $user AppBundle\Entity\User */
$user = $userManager->createUser();

This should overwrite PhpStorms previous assumption of what this type is and then find your method in the if condition below. If you take my first advice you don't have to do that, because you don't have to call the addHumidor() method anyway.

As to why this is necessary is probably a bit long winded the basic gist is, php is dynamically typed and PhpStorm can never 100% know what a method will actually return during runtime, because PHP does not enforce a method to always return the same thing. That's why PhpStorm has to guess and usually takes the docblock (or with php 7: specified return types) as it's most authoritative source, because this is obviously what the developer intends to return and what should be expected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM