Is there a way that the below code can be shortened? It's starting to look a bit messy and I wanted to know if there was a better way.
/**
* Update user.
*
* @param $request
* @param $id
* @return mixed
*/
public function updateUser($request, $id)
{
// Get user
$user = $this->user->find($id);
// Sync job titles
if($request->has('job_title'))
{
$user->jobTitles()->sync((array)$request->get('job_title'));
} else {
$user->jobTitles()->detach();
}
// Sync employee types
if($request->has('employee_type'))
{
$user->employeeTypes()->sync((array)$request->get('employee_type'));
} else {
$user->employeeTypes()->detach();
}
if($request->has('status')) {
$data = $request->only('first_name', 'last_name', 'email', 'status');
} else {
$data = $request->only('first_name', 'last_name', 'email');
}
// Save user changes
return $this->user->whereId($id)->update($data);
}
Any help would be appreciated.
Here is what I would have done:
$data
variable and overridden it if necessary.Code:
public function updateUser($request, $id)
{
$user = $this->user->find($id);
$data = $request->only('first_name', 'last_name', 'email');
$this->syncJobTitles($user);
$this->syncEmployeeTypes($user);
if($request->has('status')) {
$data['status'] = $request->status;
}
return $user->update($data);
}
private function syncJobTitles($user)
{
if(request()->has('job_title'))
{
$user->jobTitles()->sync((array) request()->get('job_title'));
} else {
$user->jobTitles()->detach();
}
}
private function syncEmployeeTypes($user)
{
if(request()->has('employee_type'))
{
$user->employeeTypes()->sync((array) request()->get('employee_type'));
} else {
$user->employeeTypes()->detach();
}
}
There are different ways to refactor that code:
If that code is only used on that part of your code you could leave it there or
Option 1 Move that business logic to the user model
class User extends Eloquent
{
...
public function applySomeRule($request)
{
if($request->has('job_title')) {
$this->jobTitles()->sync((array)$request->get('job_title'));
} else {
$this->jobTitles()->detach();
}
// Sync employee types
if($request->has('employee_type')) {
$this->employeeTypes()->sync((array)$request->get('employee_type'));
} else {
$this->employeeTypes()->detach();
}
}
}
And your controller could finish like
public function updateUser($request, $id)
{
// Get user
$user = $this->user->find($id);
$user->applySomeRule($request);
if($request->has('status')) {
$data = $request->only('first_name', 'last_name', 'email', 'status');
} else {
$data = $request->only('first_name', 'last_name', 'email');
}
// Save user changes
return $this->user->whereId($id)->update($data);
}
Option 2 If that business logic is used on different controller methods you can use Middlewares, so that you move that logic to middleware and in your route definition you use the middleware you created, let's say SomeRuleMiddleware.
Your routes would look like:
Route::put('user/{id}', [
'middleware' => 'SomeRuleMiddleware',
'uses' => 'YourController@updateUser'
]);
Option 3 You could move all your business logic to Repositories (read about Repository Pattern) and SOLID principles, that way your logic and rules will keep on Repositories and your controllers would keep clean, something like this:
class YourController extends Controller
{
protected $userRepo;
public function __construct(UserRepository $userRepo)
{
$this->userRepo = $userRepo;
}
public function updateUser($request, $id)
{
$data = $request->all();
$result = $this->userRepo->updateUser($id, $data);
return $result;
}
}