PHP-在PHP,Angular和HTTP之间传递信息的问题?

I'm working on a Laravel PHP site, and am getting an error when trying to add a user to a cell in a table

The error says:

An error has occurred adding your contact. If the problem persists, please contact us.

and is displayed in a red 'ribbon' that pops up just below the browser address bar for a few seconds when trying to select a new user from the drop down.

I have seen a couple of similar questions on SO, but can't see how any of the answers apply to what's going on here...

In the HTML, the table column whose cell value I am trying to update is done via a form that pops up in a dialog box when pressing the 'Edit' icon in the cell:

<div class="provTaxContacts__row">
    <form [formGroup]="newContactForm" class="provTaxContacts__col provTaxContacts__new-contact">
        <label>Add new contact</label>
        <div class="provTaxContacts__new-contact-fields">
            <input class="provTaxContacts__new-contact-field provTaxContacts__name" [class.error]="newContactFormErrors.contactFirstName" placeholder="First name" type="text" autocomplete="given-name" formControlName="contactFirstName" />
            <input class="provTaxContacts__new-contact-field provTaxContacts__name" [class.error]="newContactFormErrors.contactLastName" placeholder="Last name" type="text" autocomplete="family-name" formControlName="contactLastName" />
            <input class="provTaxContacts__new-contact-field provTaxContacts__email" [class.error]="newContactFormErrors.contactEmail" placeholder="Email address" type="email" autocomplete="email" formControlName="contactEmail" />
            <button class="btn btn-primary provTaxContacts__new-contact-button" type="button" (click)="onNewContactAdd(taxpayer.accountId)">Add contact</button>
            <div *ngIf="addContactLoading" class="spinner-loading"></div>
        </div>
    </form>
</div>

The onNewContactAdd() function that's called when pressing the 'Add Contact' button is defined in a Typescript file called tax-reminder.ts, and as well as handling what happens to the browser on the front-end, it also calls the function addUserToAccount() from user.service.ts. It is what's displaying the error in the browser, and is defined with:

onNewContactAdd(accountId: number) {
    const firstName = this.newContactForm.get('contactFirstName').value;
    const lastName = this.newContactForm.get('contactLastName').value;
    const email = this.newContactForm.get('contactEmail').value;
    // Reset error states
    this.resetContactFormErrors();

    // Check for form errors
    if (!firstName || Validate.isEmpty(firstName) || !Validate.lettersAndSpaces(firstName)) {
        this.newContactFormErrors.contactFirstName = true;
    } else {
        this.newContactFormErrors.contactFirstName = false;
    }

    if (!lastName || Validate.isEmpty(lastName) || !Validate.lettersAndSpaces(lastName)) {
        this.newContactFormErrors.contactLastName = true;
    } else {
        this.newContactFormErrors.contactLastName = false;
    }

    if (Validate.isEmpty(email) || !Validate.emailRegex.test(email)) {
        this.newContactFormErrors.contactEmail = true;
    } else {
        this.newContactFormErrors.contactEmail = false;
    }

    // If there are any errors at this stage, Don't add
    if (this.newContactFormErrors.contactFirstName || this.newContactFormErrors.contactLastName || this.newContactFormErrors.contactEmail) {
        return
    }

    // Reset errors, just in case there were previous erros that we now know have been resolved
    this.resetContactFormErrors();
    this.addContactLoading = true;
    // If all is valid, send a request to create the new contact
    this.userService.addUserToAccount([{firstName, lastName, email, role: 'FULL'}], 'FULL', accountId)
        .subscribe(
            (response: any) => {
                this.addContactLoading = false;

                // Reset the add contact form so that the user can add more
                this.newContactForm.patchValue({
                    contactFirstName: '',
                    contactLastName: '',
                    contactEmail: '',
                });

                // If the new contact's email address is already in the on-page list do nothing
                if (_.find(this.contacts[accountId], {email})) {
                    return;
                } else {
                    // If the request is succcessful, add the new contact to the list of contacts
                    this.contacts[accountId].push({
                        accountId,
                        email,
                        firstName,
                        groupTag: 'FULL',
                        lastName,
                        provTaxManager: 0,
                                                    provTaxPaymentsContact: 0,
                                                    userId: response.userId,
                                                    //transactionContactId,
                    });
                }
            },
            error => {
                console.log("Error: " + error);
                const message = new Message();
                message.type = MessageType.ERROR;
                message.message = 'An error has occurred adding your contact. If the problem persists please contact us.';
                this.messagingService.emitMessage(message);
            }
        )
}

In the browser console, I can see the following output in the Network-> Preview tab:

array:9 [
"userId" => 9561
"title" => null
"firstName" => "Shane"
"lastName" => "Williams"
"workPhone" => null
"mobilePhone" => null
"email" => "shane@williams.com"
"userTypeId" => 3
"login" => array:3 [
"loginId" => 9449
"loginName" => "shane@williams.com"
"userId" => 9561
]
]

Which shows that the details I entered into the form have been collected, and a new user ID has been assigned.

That output is coming from a dd() I have in the addAccountUser() PHP function:

public function addAccountUser( AddAccountUsersRequest $request )
{
  $users = $request->input('users');
  $type = $request->input('type');
  $accountId = $request->input('accountId');

  $userType = $type == 'taxfirm-agent' ? UserType::where('userTypeTag', 'AGENT')->first() : UserType::where('userTypeTag', 'DIRECT')->first();
  $messages = array();
  $hasWarningMessages = false;

  try
  {
      DB::beginTransaction();

        foreach ($users as $userRaw)
        {

              $details = array(
                  'firstName' => $userRaw['firstName'],
                  'lastName'  => $userRaw['lastName'],
                  'email'     => $userRaw['email'],
                  'password'  => uniqid(),
                  'userTypeId' => $userType->userTypeId,
                  'accountId' => (!empty($accountId)) ? $accountId : null
              );
        $propertyValues = array();

        // Adding tax agent
        if ($type == 'taxfirm-agent') {
            $group = $userRaw['role'];
            $rv = $this->addTaxfirmAgent($details, $group);
        }
        else if($type == 'taxfirm-direct') {
            $rv = $this->addTaxfirmDirectContact($details);
        }
        else {
            $group = $userRaw['role'];
            $rv = $this->addTaxpayerDirectContact($details, $group);
        }

        DB::commit();
        dd($rv['user']->toArray()); 

        if ($rv['status'] !== 'SUCCESS') {
            if (!isset($messages[$rv['status']])) {
              $messages[$rv['status']] = array(
                'message' => StatusMessage::getMessage($rv['status']),
                'data' => [],
            //dd($messages);
              );
            }

            $messages[$rv['status']]['data'][] = [$userRaw['email'], ucfirst($userRaw['firstName']), ucfirst($userRaw['lastName'])];
        //dd($messages); // success is true at this point, users are null


            if (!$hasWarningMessages)
            {
              $hasWarningMessages = true;
            }
        }
        }
    }
      catch(\Exception $e)
      {
          DB::rollback();
        return response()->json(array(
          'success' => false,
          'exceptionCode' => $e->getCode(),
          'exceptionMessage' => $e->getMessage().' - '.$e->getFile().' - '.$e->getLine(),
          'userId' => $userId // Try returning the userId too...
        ), 400);
      }

      $outputMsg = array();
      foreach ($messages as $value) {
        $outputMsg[] = $value;
      }
      //dd($users);

      return response()->json(array(
        'success' => true,
        'hasWarningMessages' => $hasWarningMessages,
        'result' => $outputMsg,
        //'users' => $rv['user']->user, /*ERF(18/09/2018 @ 1630) Change to userId */
        'userId' => $rv['user']->userId,
      ));
    }

I don't fully understand how the JavaScript, PHP & HTTP are all interacting here, or why the PHP debug appears to be showing the new contact created successfully, and yet I still get the error in the browser.

Can anyone point me in the right direction here? Why is the contact seemingly created, and yet I get the error, as well as the contact not being displayed in the drop down box as I am expecting?

Edit

So, I think that the issue I'm having here is not to do with the PHP itself- as that function seems to be returning the correct information (the console output given when I added the line dd($rv['user']->toArray()) at the end of the function showed all of the details for the user I had just added correctly), but rather to do with the Angular that should be updating the front end, to display the new user in the drop down.

That function is defined as follows:

this.userService.addUserToAccount([{firstName, lastName, email, role: 'FULL'}], 'FULL', accountId)
.subscribe(
    (response: any) => {
        this.addContactLoading = false;

        // Reset the add contact form so that the user can add more
        this.newContactForm.patchValue({
            contactFirstName: '',
            contactLastName: '',
            contactEmail: '',
        });

        // If the new contact's email address is already in the on-page list do nothing
        if (_.find(this.contacts[accountId], {email})) {
            return;
        } else {
            // If the request is succcessful, add the new contact to the list of contacts
            this.contacts[accountId].push({
                accountId,
                email,
                firstName,
                groupTag: 'FULL',
                lastName,
                provTaxManager: 0,
                provTaxPaymentsContact: 0,
                userId: response.userId,
                //transactionContactId,
            });
       }
    },
    error => {
        console.log("Error: " + error);
        const message = new Message();
        message.type = MessageType.ERROR;
        message.message = 'An error has occurred adding your contact. If the problem persists please contact us.';
        this.messagingService.emitMessage(message);
    }
)

I think I need to add a call to reload this page element at the end of the else statement in this function... How would I do that?

Edit

So, it seems that although the contact appears to be created, the HTTP response I'm getting is actually the error- as I can see the An error has occurred adding your contact. If the problem persists please contact us. message in the browser... Why is it that the HTTP response is failing? How can I resolve this?

I added a console.log() to display the error in the console, and it's showing the following output:

unparsable response

Error: SyntaxError: Unexpected token < in JSON at position 0

I don't understand where this error is coming from... any ideas?