I'm trying to understand how to use "fat model, skinny controller" in Laravel 5.2. Basically, I mostly understand the why, and the what, but not the how. I've been Googling for a while, and I have found several pages describing why (and some pages describing why not) and what, but no pages that makes it easy to understand how you create a fat model with skinny controllers.
I have created a extremely basic Todo-list, no login or validation, just the most basic todo-note functionality. This application basically uses "skinny model, fat controllers" and I want to rewrite the app so that it uses "fat model, skinny controllers" instead.
I have three tables in the MySQL-database:
When I created the migrations for the tables, I used $table->foreign('user_id')->references('id')->on('users');
and $table->foreign('project_id')->references('id')->on('projects');
for the notes table migration. For some reason it did not work, so in the database notes.user_id
and notes.project_id
are not foreign keys to users.id
and projects.id
, which was the idea from the beginning. I'm guessing that it doesn't really matter for my questions below, but if it does, someone please tell me so I can try to fix that.
I have the following models (doc blocks removed)
app\User.php:
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function notes()
{
return $this->hasMany(Note::class);
}
}
app\Project.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
public function notes()
{
return $this->hasMany(Note::class);
}
}
app\Note.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Note extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
public function project()
{
return $this->belongsTo(Project::class);
}
}
I have the following controllers (doc blocks removed)
app\Http\Controllers\UserController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\User;
use Response;
class UserController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$users = User::orderBy('uname', 'asc')->get()->toArray();
$response = [];
foreach ($users as $user) {
$this_row = array(
'id' => $user['id'],
'name' => $user['uname'],
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
}
app\Http\Controllers\ProjectController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Project;
use Response;
class ProjectController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$projects = Project::orderBy('pname', 'asc')->get()->toArray();
$response = [];
foreach ($projects as $project) {
$this_row = array(
'id' => $project['id'],
'name' => $project['pname'],
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
}
app\Http\Controllers\NoteController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Note;
use App\User;
use App\Project;
use Input;
use Response;
use Redirect;
class NoteController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$notes = Note::where('removed', 0)
->orderBy('time_created', 'asc')->get()->toArray();
$response = [];
foreach ($notes as $note) {
$user = User::find($note['user_id']); // Username for note
$project = Project::find($note['project_id']); // Project name
$this_row = array(
'id' => $note['id'],
'user' => $user['uname'],
'project' => $project['pname'],
'content' => $note['content'],
'completed' => $note['completed'],
'created' => $note['time_created'],
'deadline' => $note['time_deadline']
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
public function destroy(Request $request)
{
try {
$statusCode = 200;
$note = Note::find($request->id);
$note->removed = 1;
$note->save();
} catch (Exception $e) {
$statusCode = 400;
} finally {
return $statusCode;
}
}
public function edit($request)
{
try {
$statusCode = 200;
$note = Note::find($request);
$response = array(
'id' => $note['id'],
'content' => $note['content'],
'completed' => $note['completed'],
'deadline' => $note['time_deadline']
);
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
public function update(Request $request)
{
try {
$statusCode = 200;
$note = Note::find($request->id);
$note->content = $request->content;
$note->time_deadline = $request->deadline;
if ($request->completed == "true") {
$note->completed = 1;
} else {
$note->completed = 0;
}
$note->save();
} catch (Exception $e) {
$statusCode = 400;
} finally {
return $statusCode;
}
}
public function store(Request $request)
{
try {
$statusCode = 200;
$note = new Note;
$note->user_id = $request->user;
$note->project_id = $request->project;
$note->content = $request->content;
$note->time_deadline = $request->deadline;
$note->save();
} catch (Exception $e) {
$statusCode = 400;
} finally {
return $statusCode;
}
}
}
Finally, this is my app/Http/routes.php (comments removed)
<?php
Route::get('/', function () {
return view('index');
});
Route::get('/notes', 'NoteController@index');
Route::get('/notes/{id}', 'NoteController@edit');
Route::delete('/notes', 'NoteController@destroy');
Route::put('/notes', 'NoteController@store');
Route::post('/notes', 'NoteController@update');
Route::get('/projects', 'ProjectController@index');
Route::get('/users', 'UserController@index');
Route::group(['middleware' => ['web']], function () {
//
});
The complete code can be found at my GitHub here.
I'm using Angular to receive the JSON sent by the controllers. This works fine for my current page but as you can see, my controllers have a lot of logic, which I would like to move to the model. I don't understand how I do this, so here's my questions:
Your skinny controller could be the following, which will do the same what you did:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Project;
class ProjectController extends Controller
{
public function index()
{
$projects = Project::orderBy('pname', 'asc')->get(['id', 'name']);
return response()->make($projects);
}
}
But as Fabio mentioned, if you want to go further, checkout repositories. Here is a good article: https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/
In most cases I'm wrapping repositories into services to create the business logic. Controllers just handle routing, and models only contains relations or mutators and accessors. But it could differ by development methods.
Also, don't make db queries in foreach loops, take the advantage of Eloquent with, forexample:
$notes = Note::where('removed', 0)
->with(['user', 'project'])
->orderBy('time_created', 'asc')->get();
And you can access, like this:
foreach($notes as $note)
{
echo $note->user->uname;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With