Symfony controller that registers a user via HTTP-POST

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite
1












This is the code I have written for one of my API routes. I feel like my controller is too big and the function does too much. What can I do to make my adhere to SOLID principles and be more maintainable/readable?



/**
* @Route("/registration", name="registration")
* @Method("POST")
* @throws UniqueConstraintViolationException
* @param Request $request
* @return JsonResponse
*/
public function registrationAction(Request $request, UserPasswordEncoderInterface $encoder)

// Build base response
$response = [
"success" => false,
"message" => "",
"user_id" => null,
"errors" =>
];

// Put blanks for keys not present in the request
// This is so we can validate this using Symfony's validator class
foreach(self::REQUIRED_KEYS as $key)
if (!array_key_exists($key, $request->request->all()))
$request->request->set($key, "");



// Get validator and build array of constraints
$validator = Validation::createValidator();
$constraint = new AssertCollection([
"username" => new AssertNotBlank(['message' => "Username is required."]),
"email" => [
new AssertEmail(["message" => "Email must be a valid email address."]),
new AssertNotBlank(["message" => "Email is required."])
],
"address1" => new AssertNotBlank(['message' => "Address1 is required."]),
"city" => new AssertNotBlank(['message' => "City is required."]),
"state" => new AssertNotBlank(['message' => "State is required."]),
"zip" => new AssertNotBlank(['message' => "Zip is required."]),
]);
$constraint->allowExtraFields = true;

$errors = $validator->validate($request->request->all(), $constraint);

// If there are errors, return the errors as a response
// If there are no errors, register the user and return the ID
if (count($errors) > 0)
foreach($errors as $e) $response['errors'] = $e->getMessage();
$response['message'] = "Submitted user failed validation.";
else
$user = new User($request->request->all());
$encodedPassword = $encoder->encodePassword($user, 'password');
$user->setPassword($encodedPassword);

$em = $this->getDoctrine()->getManager();
try
$user->setEnabled(true);
$em->persist($user);
$em->flush();
$response['success'] = true;
$response['user_id'] = $user->getId();
catch (UniqueConstraintViolationException $e)
preg_match('/(?<=Duplicate entry ')[^']*/', $e->getMessage(), $matches);
$response['message'] = "Unique constraint violation exception";
$response['errors'] = sprintf('%s already exists in the database.', $matches[0]);



return new JsonResponse($response);



My initial hunch is that I should put this into a service and break it up. But it seems like I would just be copying and pasting this code into class.







share|improve this question















  • 1




    Question: How are you generating the form?
    – David Patterson
    Feb 3 at 19:57
















up vote
3
down vote

favorite
1












This is the code I have written for one of my API routes. I feel like my controller is too big and the function does too much. What can I do to make my adhere to SOLID principles and be more maintainable/readable?



/**
* @Route("/registration", name="registration")
* @Method("POST")
* @throws UniqueConstraintViolationException
* @param Request $request
* @return JsonResponse
*/
public function registrationAction(Request $request, UserPasswordEncoderInterface $encoder)

// Build base response
$response = [
"success" => false,
"message" => "",
"user_id" => null,
"errors" =>
];

// Put blanks for keys not present in the request
// This is so we can validate this using Symfony's validator class
foreach(self::REQUIRED_KEYS as $key)
if (!array_key_exists($key, $request->request->all()))
$request->request->set($key, "");



// Get validator and build array of constraints
$validator = Validation::createValidator();
$constraint = new AssertCollection([
"username" => new AssertNotBlank(['message' => "Username is required."]),
"email" => [
new AssertEmail(["message" => "Email must be a valid email address."]),
new AssertNotBlank(["message" => "Email is required."])
],
"address1" => new AssertNotBlank(['message' => "Address1 is required."]),
"city" => new AssertNotBlank(['message' => "City is required."]),
"state" => new AssertNotBlank(['message' => "State is required."]),
"zip" => new AssertNotBlank(['message' => "Zip is required."]),
]);
$constraint->allowExtraFields = true;

$errors = $validator->validate($request->request->all(), $constraint);

// If there are errors, return the errors as a response
// If there are no errors, register the user and return the ID
if (count($errors) > 0)
foreach($errors as $e) $response['errors'] = $e->getMessage();
$response['message'] = "Submitted user failed validation.";
else
$user = new User($request->request->all());
$encodedPassword = $encoder->encodePassword($user, 'password');
$user->setPassword($encodedPassword);

$em = $this->getDoctrine()->getManager();
try
$user->setEnabled(true);
$em->persist($user);
$em->flush();
$response['success'] = true;
$response['user_id'] = $user->getId();
catch (UniqueConstraintViolationException $e)
preg_match('/(?<=Duplicate entry ')[^']*/', $e->getMessage(), $matches);
$response['message'] = "Unique constraint violation exception";
$response['errors'] = sprintf('%s already exists in the database.', $matches[0]);



return new JsonResponse($response);



My initial hunch is that I should put this into a service and break it up. But it seems like I would just be copying and pasting this code into class.







share|improve this question















  • 1




    Question: How are you generating the form?
    – David Patterson
    Feb 3 at 19:57












up vote
3
down vote

favorite
1









up vote
3
down vote

favorite
1






1





This is the code I have written for one of my API routes. I feel like my controller is too big and the function does too much. What can I do to make my adhere to SOLID principles and be more maintainable/readable?



/**
* @Route("/registration", name="registration")
* @Method("POST")
* @throws UniqueConstraintViolationException
* @param Request $request
* @return JsonResponse
*/
public function registrationAction(Request $request, UserPasswordEncoderInterface $encoder)

// Build base response
$response = [
"success" => false,
"message" => "",
"user_id" => null,
"errors" =>
];

// Put blanks for keys not present in the request
// This is so we can validate this using Symfony's validator class
foreach(self::REQUIRED_KEYS as $key)
if (!array_key_exists($key, $request->request->all()))
$request->request->set($key, "");



// Get validator and build array of constraints
$validator = Validation::createValidator();
$constraint = new AssertCollection([
"username" => new AssertNotBlank(['message' => "Username is required."]),
"email" => [
new AssertEmail(["message" => "Email must be a valid email address."]),
new AssertNotBlank(["message" => "Email is required."])
],
"address1" => new AssertNotBlank(['message' => "Address1 is required."]),
"city" => new AssertNotBlank(['message' => "City is required."]),
"state" => new AssertNotBlank(['message' => "State is required."]),
"zip" => new AssertNotBlank(['message' => "Zip is required."]),
]);
$constraint->allowExtraFields = true;

$errors = $validator->validate($request->request->all(), $constraint);

// If there are errors, return the errors as a response
// If there are no errors, register the user and return the ID
if (count($errors) > 0)
foreach($errors as $e) $response['errors'] = $e->getMessage();
$response['message'] = "Submitted user failed validation.";
else
$user = new User($request->request->all());
$encodedPassword = $encoder->encodePassword($user, 'password');
$user->setPassword($encodedPassword);

$em = $this->getDoctrine()->getManager();
try
$user->setEnabled(true);
$em->persist($user);
$em->flush();
$response['success'] = true;
$response['user_id'] = $user->getId();
catch (UniqueConstraintViolationException $e)
preg_match('/(?<=Duplicate entry ')[^']*/', $e->getMessage(), $matches);
$response['message'] = "Unique constraint violation exception";
$response['errors'] = sprintf('%s already exists in the database.', $matches[0]);



return new JsonResponse($response);



My initial hunch is that I should put this into a service and break it up. But it seems like I would just be copying and pasting this code into class.







share|improve this question











This is the code I have written for one of my API routes. I feel like my controller is too big and the function does too much. What can I do to make my adhere to SOLID principles and be more maintainable/readable?



/**
* @Route("/registration", name="registration")
* @Method("POST")
* @throws UniqueConstraintViolationException
* @param Request $request
* @return JsonResponse
*/
public function registrationAction(Request $request, UserPasswordEncoderInterface $encoder)

// Build base response
$response = [
"success" => false,
"message" => "",
"user_id" => null,
"errors" =>
];

// Put blanks for keys not present in the request
// This is so we can validate this using Symfony's validator class
foreach(self::REQUIRED_KEYS as $key)
if (!array_key_exists($key, $request->request->all()))
$request->request->set($key, "");



// Get validator and build array of constraints
$validator = Validation::createValidator();
$constraint = new AssertCollection([
"username" => new AssertNotBlank(['message' => "Username is required."]),
"email" => [
new AssertEmail(["message" => "Email must be a valid email address."]),
new AssertNotBlank(["message" => "Email is required."])
],
"address1" => new AssertNotBlank(['message' => "Address1 is required."]),
"city" => new AssertNotBlank(['message' => "City is required."]),
"state" => new AssertNotBlank(['message' => "State is required."]),
"zip" => new AssertNotBlank(['message' => "Zip is required."]),
]);
$constraint->allowExtraFields = true;

$errors = $validator->validate($request->request->all(), $constraint);

// If there are errors, return the errors as a response
// If there are no errors, register the user and return the ID
if (count($errors) > 0)
foreach($errors as $e) $response['errors'] = $e->getMessage();
$response['message'] = "Submitted user failed validation.";
else
$user = new User($request->request->all());
$encodedPassword = $encoder->encodePassword($user, 'password');
$user->setPassword($encodedPassword);

$em = $this->getDoctrine()->getManager();
try
$user->setEnabled(true);
$em->persist($user);
$em->flush();
$response['success'] = true;
$response['user_id'] = $user->getId();
catch (UniqueConstraintViolationException $e)
preg_match('/(?<=Duplicate entry ')[^']*/', $e->getMessage(), $matches);
$response['message'] = "Unique constraint violation exception";
$response['errors'] = sprintf('%s already exists in the database.', $matches[0]);



return new JsonResponse($response);



My initial hunch is that I should put this into a service and break it up. But it seems like I would just be copying and pasting this code into class.









share|improve this question










share|improve this question




share|improve this question









asked Jan 18 at 0:23









Robert Calove

1654




1654







  • 1




    Question: How are you generating the form?
    – David Patterson
    Feb 3 at 19:57












  • 1




    Question: How are you generating the form?
    – David Patterson
    Feb 3 at 19:57







1




1




Question: How are you generating the form?
– David Patterson
Feb 3 at 19:57




Question: How are you generating the form?
– David Patterson
Feb 3 at 19:57










1 Answer
1






active

oldest

votes

















up vote
3
down vote














I feel like my controller is too big and the function does too much.




I think you're right there. Your validation rules shouldn't be in the controller, but in separate classes. That makes re-using them much easier. I




My initial hunch is that I should put this into a service and break it
up. But it seems like I would just be copying and pasting this code
into class.




You're right here. Just moving code from your controller to a service makes no sense.



Why aren't you using Symfony Forms? It does exactly the job you're doing here: take the Request and some rules and tell you if the request matches your validation rules.



You can create an object (a Doctrine entity or a Data Transfer Object, DTO), add the constraints to it by using annotations.



See this to examples from https://stovepipe.systems/post/avoiding-entities-in-forms:



Your DTO:



class ChangeUsernameData

/**
* @SomeCustomAssertUnique(entity="AppEntityAuthentication", field="username")
* @AssertLength(5, 16)
**/
public $newUsername;



Your controller:



$changeUsername = new ChangeUsernameData();
$form = $this->formFactory->create(ChangeUsernameType::class, $changeUsername);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid())
$authentication->setUsername($changeUsername->newUsername);
$this->em->flush($authentication);

// redirect






share|improve this answer





















    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185355%2fsymfony-controller-that-registers-a-user-via-http-post%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    3
    down vote














    I feel like my controller is too big and the function does too much.




    I think you're right there. Your validation rules shouldn't be in the controller, but in separate classes. That makes re-using them much easier. I




    My initial hunch is that I should put this into a service and break it
    up. But it seems like I would just be copying and pasting this code
    into class.




    You're right here. Just moving code from your controller to a service makes no sense.



    Why aren't you using Symfony Forms? It does exactly the job you're doing here: take the Request and some rules and tell you if the request matches your validation rules.



    You can create an object (a Doctrine entity or a Data Transfer Object, DTO), add the constraints to it by using annotations.



    See this to examples from https://stovepipe.systems/post/avoiding-entities-in-forms:



    Your DTO:



    class ChangeUsernameData

    /**
    * @SomeCustomAssertUnique(entity="AppEntityAuthentication", field="username")
    * @AssertLength(5, 16)
    **/
    public $newUsername;



    Your controller:



    $changeUsername = new ChangeUsernameData();
    $form = $this->formFactory->create(ChangeUsernameType::class, $changeUsername);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid())
    $authentication->setUsername($changeUsername->newUsername);
    $this->em->flush($authentication);

    // redirect






    share|improve this answer

























      up vote
      3
      down vote














      I feel like my controller is too big and the function does too much.




      I think you're right there. Your validation rules shouldn't be in the controller, but in separate classes. That makes re-using them much easier. I




      My initial hunch is that I should put this into a service and break it
      up. But it seems like I would just be copying and pasting this code
      into class.




      You're right here. Just moving code from your controller to a service makes no sense.



      Why aren't you using Symfony Forms? It does exactly the job you're doing here: take the Request and some rules and tell you if the request matches your validation rules.



      You can create an object (a Doctrine entity or a Data Transfer Object, DTO), add the constraints to it by using annotations.



      See this to examples from https://stovepipe.systems/post/avoiding-entities-in-forms:



      Your DTO:



      class ChangeUsernameData

      /**
      * @SomeCustomAssertUnique(entity="AppEntityAuthentication", field="username")
      * @AssertLength(5, 16)
      **/
      public $newUsername;



      Your controller:



      $changeUsername = new ChangeUsernameData();
      $form = $this->formFactory->create(ChangeUsernameType::class, $changeUsername);
      $form->handleRequest($request);

      if ($form->isSubmitted() && $form->isValid())
      $authentication->setUsername($changeUsername->newUsername);
      $this->em->flush($authentication);

      // redirect






      share|improve this answer























        up vote
        3
        down vote










        up vote
        3
        down vote










        I feel like my controller is too big and the function does too much.




        I think you're right there. Your validation rules shouldn't be in the controller, but in separate classes. That makes re-using them much easier. I




        My initial hunch is that I should put this into a service and break it
        up. But it seems like I would just be copying and pasting this code
        into class.




        You're right here. Just moving code from your controller to a service makes no sense.



        Why aren't you using Symfony Forms? It does exactly the job you're doing here: take the Request and some rules and tell you if the request matches your validation rules.



        You can create an object (a Doctrine entity or a Data Transfer Object, DTO), add the constraints to it by using annotations.



        See this to examples from https://stovepipe.systems/post/avoiding-entities-in-forms:



        Your DTO:



        class ChangeUsernameData

        /**
        * @SomeCustomAssertUnique(entity="AppEntityAuthentication", field="username")
        * @AssertLength(5, 16)
        **/
        public $newUsername;



        Your controller:



        $changeUsername = new ChangeUsernameData();
        $form = $this->formFactory->create(ChangeUsernameType::class, $changeUsername);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid())
        $authentication->setUsername($changeUsername->newUsername);
        $this->em->flush($authentication);

        // redirect






        share|improve this answer














        I feel like my controller is too big and the function does too much.




        I think you're right there. Your validation rules shouldn't be in the controller, but in separate classes. That makes re-using them much easier. I




        My initial hunch is that I should put this into a service and break it
        up. But it seems like I would just be copying and pasting this code
        into class.




        You're right here. Just moving code from your controller to a service makes no sense.



        Why aren't you using Symfony Forms? It does exactly the job you're doing here: take the Request and some rules and tell you if the request matches your validation rules.



        You can create an object (a Doctrine entity or a Data Transfer Object, DTO), add the constraints to it by using annotations.



        See this to examples from https://stovepipe.systems/post/avoiding-entities-in-forms:



        Your DTO:



        class ChangeUsernameData

        /**
        * @SomeCustomAssertUnique(entity="AppEntityAuthentication", field="username")
        * @AssertLength(5, 16)
        **/
        public $newUsername;



        Your controller:



        $changeUsername = new ChangeUsernameData();
        $form = $this->formFactory->create(ChangeUsernameType::class, $changeUsername);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid())
        $authentication->setUsername($changeUsername->newUsername);
        $this->em->flush($authentication);

        // redirect







        share|improve this answer













        share|improve this answer



        share|improve this answer











        answered May 28 at 12:05









        Stephan Vierkant

        1414




        1414






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185355%2fsymfony-controller-that-registers-a-user-via-http-post%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Chat program with C++ and SFML

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            Will my employers contract hold up in court?