Derek Derek - 5 days ago 4
PHP Question

Adding company registration to SaaS app Laravel

I am coming from codeigniter to laravel and still fairly new so excuse me if this is obvious. I'm struggling with something that seems to be pretty simple but cannot find any info online but have found a few packages that come close.

I have added an input field on registration to capture the company name, once they click register it should add the user info to the user table like it does but also add company_name to the company_name column of the companies table.

Company Table:

+----+----------------+----------------+--------------+
| ID | company_name | created_at | updated_at |
+----+----------------+----------------+--------------+


User Table:

+----+------------+------+-------+----------+----------------+------------+------------+
| ID | company_id | name | email | password | remember_token | created_at | updated_at |
+----+------------+------+-------+----------+----------------+------------+------------+


Companies Model:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Companies extends Model
{
//
//
protected $fillable = [
'company_name',
];

}


User Model:

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Zizaco\Entrust\Traits\EntrustUserTrait;

class User extends Authenticatable
{
use EntrustUserTrait;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];

/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];

public function Company()
{
return $this->hasMany('App\Companies');
}
}


And in my AuthController:

namespace App\Http\Controllers\Auth;

use App\User;
use App\Companies;
use Validator;
use App\Http\Controllers\Controller;
use App\Http\Controllers\CompanyController;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;

class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/

use AuthenticatesAndRegistersUsers, ThrottlesLogins;

/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/';

/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => ['logout', 'getLogout']]);
}

/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'company_name' => 'required|min:5|unique:companies,company_name',
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}

/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{

$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
$user->Company()->create(['company_name'=>$data['company_name']]);
$user->attachRole(1); // parameter can be an Role object, array, or id
return $user;
}
}


And finally here is the form in my register.blade.php

<div class="register-box-body">
<div class="register-box-body">
<p class="login-box-msg">Register a new membership</p>
<form action="{{ url('/auth/register') }}" method="post">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="form-group has-feedback">
<input type="text" class="form-control" placeholder="Company name" name="company_name" value="{{ old('company_name') }}"/>
<span class="glyphicon glyphicon-globe form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="text" class="form-control" placeholder="Full name" name="name" value="{{ old('name') }}"/>
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="email" class="form-control" placeholder="Email" name="email" value="{{ old('email') }}"/>
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="password" class="form-control" placeholder="Password" name="password"/>
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="password" class="form-control" placeholder="Retype password" name="password_confirmation"/>
<span class="glyphicon glyphicon-log-in form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-8">
<div class="checkbox icheck">
<label>
<input type="checkbox"> I agree to the <a href="#">terms</a>
</label>
</div>
</div><!-- /.col -->
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">Register</button>
</div><!-- /.col -->
</div>
</form>


This all seems right based on this question's answer. However when I register it just creates the user info in the
users
table with
company_id
being
0
and does not add anything to the
companies
table.

How would I go about adding creating a field on registration for user to enter
company_name
and then when saved it adds to the
companies
table and stores the
company_id
in the
users
table?


-------------------------------------------
UPDATED
-------------------------------------------


Here is my latest Auth/RegisterController.php (I guess the latest version Laravel Framework version 5.3.24 breaks Auth up in various controllers)

<?php

namespace App\Http\Controllers\Auth;

use App\User;
use App\Company;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\RegistersUsers;

class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/

use RegistersUsers;

/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/home';

/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}

/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'company_name' => 'required|unique:companies,company_name',
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}

/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{
$company = \App\Company::create(['company_name'=>$data['company_name']]);

$company->users()->create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);

return $company;

// User::create([
// 'name' => $data['name'],
// 'email' => $data['email'],
// 'password' => bcrypt($data['password']),
// ]);
}
}

Answer

I see now. You are doing it in wrong direction. You have to make company first. Then a user. Something like this:

   $company = \App\Companies::create(['company_name'=>$data['company_name']]);
   $company->users()->create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);

If you think about it, it makes sense. If you create an user first, you can't populate company_id as company does not exist yet.

One thing I strongly recommend is to name your models in singular - Company not Companies as this is common convention.

Also, make sure you have defined users() method on Companies model

public function users()
    {
        return $this->hasMany(\App\User::class);
    }

This method is in plural as one company can have many users. It is not required but makes more sense.

Also, relationship on User model (your method Company()) should be:

public function company()
    {
        return $this->belongsTo(\App\Company::class);
    }

First, convention is to write method names starting with lowercase letter (camelCase). Second, your User model has hasMany relationship defined - which is wrong. User does not have many companies, but he belongs to company.

If for any reason you want to create user first, then the approach would be to create an user, create a company and then take id of the company and update user.

Something like this:

$user = \App\Users::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
$company = \App\Companies::create(['company_name'=>$data['company_name']]);
$user->company_id = $company->id;
$user->save();

-------------- UPDATE BASED ON QUESTION UPDATE ----------------

Make sure you return $user on create() method, not a $company, as it expects user to be returned.

$company = \App\Companies::create(['company_name'=>$data['company_name']]);
$user = $company->users()->create([
                'name' => $data['name'],
                'email' => $data['email'],
                'password' => bcrypt($data['password']),
            ]);
return $user;
Comments