I am creating a laravel todo application. In my controller there's have different methods but all codes in it are almost same. In notCompleted method and completed method there have 1 more different where clause. Except it all codes are same. How can I avoid code duplication here?
public function all()
{
$user_id = $this->user_id;
$todos = $this->todos
->where('user_id', $user_id)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
}
public function notCompleted()
{
$user_id = $this->user_id;
$todos = $this->todos
->where('user_id', $user_id)
->where('completed', false)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
}
public function completed()
{
$user_id = $this->user_id;
$todos = $this->todos
->where('user_id', $user_id)
->where('completed', true)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
}
I was needed three different methods, So I kept those methods and extract the codes into one methods. And may that save's a code duplication. Isn't it?
and Thanks to all who respond me :)
public function all()
{
return $this->todoStatus('all');
}
public function index()
{
return $this->todoStatus('current', false);
}
public function completed()
{
return $this->todoStatus('completed', true);
}
protected function todoStatus($completed, $status = false)
{
$user_id = $this->user_id;
if($completed === 'all') {
$todos = $this->todos
->where('user_id', $user_id)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
} else {
$todos = $this->todos
->where('user_id', $user_id)
->where('completed', $status)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
}
}
In your model you can define a scope to eliminate the duplicate. example
In Todo Model
public function scopeUserTodo($query, $userId){
return $query->where('user_id', $userId);
}
public function scopeCompleted($query, $flag){
return $query->where('completed', $flag);
}
public function scopeLatest($query){
return $query->orderBy('id','Desc');
}
Then in your controller you can change your queries to
public function all()
{
$user_id = $this->user_id;
$todos = $this->todos->userTodo($user_id)->latest()->paginate(15)
return view('todos.index', compact('todos'));
}
public function notCompleted()
{
$user_id = $this->user_id;
$todos = $this->todos->userTodo($user_id)->completed(false)
->latest()->paginate(15)
return view('todos.index', compact('todos'));
}
public function completed()
{
$user_id = $this->user_id;
$todos = $this->todos->userTodo($user_id)->completed(true)
->latest()->paginate(15)
return view('todos.index', compact('todos'));
}
You can further create a function in your controller and name it todoState and move the common code between the notCompleted and completed function there. Example
public function todoState($userId, $completed){
$todos = $this->todos->userTodo($userId)
->completed($completed)
->latest()
->paginate(15);
return $todos;
}
public function all($check, $value)
{
$user_id = $this->user_id;
if($check !== "completed"){
$todos = $this->todos
->where('user_id', $user_id)
->where('completed', $value)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
}else{
$todos = $this->todos
->where('user_id', $user_id)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
}
}
something like this? and just pass through the data on function call
You could create a simple function that takes in the few changeable variables
so something like:
private function helper($userid, $completed)
{
return $this->todos
->where('user_id', $userid)
->where('completed', $completed)
->orderBy('id', 'DESC')->paginate(15);
}
Then in your controller code:
public function notCompleted()
{
$user_id = $this->user_id;
$todos = $this->helper($user_id, false);
return view('todos.index', compact('todos'));
}
Create a function to getByCompletedStatus...
public function getByCompletedStatus($status)
{
$user_id = $this->user_id;
$todos = $this->todos
->where('user_id', $user_id)
->where('completed', $status)
->orderBy('id', 'DESC')->paginate(15);
return view('todos.index', compact('todos'));
}
Then you'll pass a true or false as required, and avoid the code duplication.